mirror of
				https://github.com/interviewstreet/go-jira.git
				synced 2025-10-30 23:47:46 +02:00 
			
		
		
		
	Add Transition API handling
Added TransitionService with 2 methods: * GetList for retrieving possible transitions for an issue * Create for creating transition and changing issue status in the process
This commit is contained in:
		| @@ -13,6 +13,7 @@ | ||||
|  | ||||
| * Authentication (HTTP Basic, OAuth, Session Cookie) | ||||
| * Create and receive issues | ||||
| * Create and retrieve issue transitions (status updates) | ||||
| * Call every API endpoint of the JIRA, even it is not directly implemented in this library | ||||
|  | ||||
| This package is not JIRA API complete (yet), but you can call every API endpoint you want. See [Call a not implemented API endpoint](#call-a-not-implemented-api-endpoint) how to do this. For all possible API endpoints of JRIA have a look at [latest JIRA REST API documentation](https://docs.atlassian.com/jira/REST/latest/). | ||||
|   | ||||
							
								
								
									
										2
									
								
								jira.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								jira.go
									
									
									
									
									
								
							| @@ -28,6 +28,7 @@ type Client struct { | ||||
| 	Issue          *IssueService | ||||
| 	Project        *ProjectService | ||||
| 	Board          *BoardService | ||||
| 	Transition     *TransitionService | ||||
| } | ||||
|  | ||||
| // NewClient returns a new JIRA API client. | ||||
| @@ -55,6 +56,7 @@ func NewClient(httpClient *http.Client, baseURL string) (*Client, error) { | ||||
| 	c.Issue = &IssueService{client: c} | ||||
| 	c.Project = &ProjectService{client: c} | ||||
| 	c.Board = &BoardService{client: c} | ||||
| 	c.Transition = &TransitionService{client: c} | ||||
|  | ||||
| 	return c, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										101
									
								
								mocks/transitions.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								mocks/transitions.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| { | ||||
|     "expand": "transitions", | ||||
|     "transitions": [ | ||||
|         { | ||||
|             "id": "2", | ||||
|             "name": "Close Issue", | ||||
|             "to": { | ||||
|                 "self": "http://localhost:8090/jira/rest/api/2.0/status/10000", | ||||
|                 "description": "The issue is currently being worked on.", | ||||
|                 "iconUrl": "http://localhost:8090/jira/images/icons/progress.gif", | ||||
|                 "name": "In Progress", | ||||
|                 "id": "10000", | ||||
|                 "statusCategory": { | ||||
|                     "self": "http://localhost:8090/jira/rest/api/2.0/statuscategory/1", | ||||
|                     "id": 1, | ||||
|                     "key": "in-flight", | ||||
|                     "colorName": "yellow", | ||||
|                     "name": "In Progress" | ||||
|                 } | ||||
|             }, | ||||
|             "fields": { | ||||
|                 "summary": { | ||||
|                     "required": false, | ||||
|                     "schema": { | ||||
|                         "type": "array", | ||||
|                         "items": "option", | ||||
|                         "custom": "com.atlassian.jira.plugin.system.customfieldtypes:multiselect", | ||||
|                         "customId": 10001 | ||||
|                     }, | ||||
|                     "name": "My Multi Select", | ||||
|                     "hasDefaultValue": false, | ||||
|                     "operations": [ | ||||
|                         "set", | ||||
|                         "add" | ||||
|                     ], | ||||
|                     "allowedValues": [ | ||||
|                         "red", | ||||
|                         "blue" | ||||
|                     ] | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             "id": "711", | ||||
|             "name": "QA Review", | ||||
|             "to": { | ||||
|                 "self": "http://localhost:8090/jira/rest/api/2.0/status/5", | ||||
|                 "description": "The issue is closed.", | ||||
|                 "iconUrl": "http://localhost:8090/jira/images/icons/closed.gif", | ||||
|                 "name": "Closed", | ||||
|                 "id": "5", | ||||
|                 "statusCategory": { | ||||
|                     "self": "http://localhost:8090/jira/rest/api/2.0/statuscategory/9", | ||||
|                     "id": 9, | ||||
|                     "key": "completed", | ||||
|                     "colorName": "green" | ||||
|                 } | ||||
|             }, | ||||
|             "fields": { | ||||
|                 "summary": { | ||||
|                     "required": false, | ||||
|                     "schema": { | ||||
|                         "type": "array", | ||||
|                         "items": "option", | ||||
|                         "custom": "com.atlassian.jira.plugin.system.customfieldtypes:multiselect", | ||||
|                         "customId": 10001 | ||||
|                     }, | ||||
|                     "name": "My Multi Select", | ||||
|                     "hasDefaultValue": false, | ||||
|                     "operations": [ | ||||
|                         "set", | ||||
|                         "add" | ||||
|                     ], | ||||
|                     "allowedValues": [ | ||||
|                         "red", | ||||
|                         "blue" | ||||
|                     ] | ||||
|                 }, | ||||
|                 "colour": { | ||||
|                     "required": false, | ||||
|                     "schema": { | ||||
|                         "type": "array", | ||||
|                         "items": "option", | ||||
|                         "custom": "com.atlassian.jira.plugin.system.customfieldtypes:multiselect", | ||||
|                         "customId": 10001 | ||||
|                     }, | ||||
|                     "name": "My Multi Select", | ||||
|                     "hasDefaultValue": false, | ||||
|                     "operations": [ | ||||
|                         "set", | ||||
|                         "add" | ||||
|                     ], | ||||
|                     "allowedValues": [ | ||||
|                         "red", | ||||
|                         "blue" | ||||
|                     ] | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										75
									
								
								transition.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								transition.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| package jira | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| // TransitionService handles transitions for JIRA issue. | ||||
| type TransitionService struct { | ||||
| 	client *Client | ||||
| } | ||||
|  | ||||
| // Wrapper struct for search result | ||||
| type transitionResult struct { | ||||
| 	Transitions []Transition `json:transitions` | ||||
| } | ||||
|  | ||||
| // Transition represents an issue transition in JIRA | ||||
| type Transition struct { | ||||
| 	ID     string                     `json:"id"` | ||||
| 	Name   string                     `json:"name"` | ||||
| 	Fields map[string]TransitionField `json:"fields"` | ||||
| } | ||||
|  | ||||
| type TransitionField struct { | ||||
| 	Required bool `json:"required"` | ||||
| } | ||||
|  | ||||
| // CreatePayload is used for creating new issue transitions | ||||
| type CreateTransitionPayload struct { | ||||
| 	Transition TransitionPayload `json:"transition"` | ||||
| } | ||||
|  | ||||
| type TransitionPayload struct { | ||||
| 	ID string `json:"id"` | ||||
| } | ||||
|  | ||||
| // GetList gets transitions available for given issue | ||||
| // | ||||
| // JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-getTransitions | ||||
| func (s *TransitionService) GetList(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) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	result := new(transitionResult) | ||||
| 	resp, err := s.client.Do(req, result) | ||||
| 	return result.Transitions, resp, err | ||||
| } | ||||
|  | ||||
| // Basic transition creation. This simply creates transition with given ID for issue | ||||
| // with given ID. It doesn't yet support anything else. | ||||
| // | ||||
| // JIRA API docs: https://docs.atlassian.com/jira/REST/latest/#api/2/issue-doTransition | ||||
| func (s *TransitionService) Create(ticketID, transitionID string) (*Response, error) { | ||||
| 	apiEndpoint := fmt.Sprintf("rest/api/2/issue/%s/transitions", ticketID) | ||||
|  | ||||
| 	payload := CreateTransitionPayload{ | ||||
| 		Transition: TransitionPayload{ | ||||
| 			ID: transitionID, | ||||
| 		}, | ||||
| 	} | ||||
| 	req, err := s.client.NewRequest("POST", apiEndpoint, payload) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	resp, err := s.client.Do(req, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return resp, nil | ||||
| } | ||||
							
								
								
									
										76
									
								
								transition_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								transition_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| package jira | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestTransitionGetList(t *testing.T) { | ||||
| 	setup() | ||||
| 	defer teardown() | ||||
|  | ||||
| 	testAPIEndpoint := "/rest/api/2/issue/123/transitions" | ||||
|  | ||||
| 	raw, err := ioutil.ReadFile("./mocks/transitions.json") | ||||
| 	if err != nil { | ||||
| 		t.Error(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	testMux.HandleFunc(testAPIEndpoint, func(w http.ResponseWriter, r *http.Request) { | ||||
| 		testMethod(t, r, "GET") | ||||
| 		testRequestURL(t, r, testAPIEndpoint) | ||||
| 		fmt.Fprint(w, string(raw)) | ||||
| 	}) | ||||
|  | ||||
| 	transitions, _, err := testClient.Transition.GetList("123") | ||||
|  | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Got error: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if transitions == nil { | ||||
| 		t.Error("Expected transition list. Got nil.") | ||||
| 	} | ||||
|  | ||||
| 	if len(transitions) != 2 { | ||||
| 		t.Errorf("Expected 2 transitions. Got %d", len(transitions)) | ||||
| 	} | ||||
|  | ||||
| 	if transitions[0].Fields["summary"].Required != false { | ||||
| 		t.Errorf("First transition summary field should not be required") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTransitionCreate(t *testing.T) { | ||||
| 	setup() | ||||
| 	defer teardown() | ||||
|  | ||||
| 	testAPIEndpoint := "/rest/api/2/issue/123/transitions" | ||||
|  | ||||
| 	transitionID := "22" | ||||
|  | ||||
| 	testMux.HandleFunc(testAPIEndpoint, func(w http.ResponseWriter, r *http.Request) { | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testRequestURL(t, r, testAPIEndpoint) | ||||
|  | ||||
| 		decoder := json.NewDecoder(r.Body) | ||||
| 		var payload CreateTransitionPayload | ||||
| 		err := decoder.Decode(&payload) | ||||
| 		if err != nil { | ||||
| 			t.Error("Got error: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		if strings.Compare(payload.Transition.ID, transitionID) != 0 { | ||||
| 			t.Errorf("Expected %s to be in payload, got %s instead", transitionID, payload.Transition.ID) | ||||
| 		} | ||||
| 	}) | ||||
| 	_, err := testClient.Transition.Create("123", transitionID) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		t.Error("Got error: %v", err) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user