mirror of
				https://github.com/interviewstreet/go-jira.git
				synced 2025-10-30 23:47:46 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			195 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package jira
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/google/go-querystring/query"
 | |
| 	"github.com/trivago/tgo/tcontainer"
 | |
| )
 | |
| 
 | |
| // CreateMetaInfo contains information about fields and their attributed to create a ticket.
 | |
| type CreateMetaInfo struct {
 | |
| 	Expand   string         `json:"expand,omitempty"`
 | |
| 	Projects []*MetaProject `json:"projects,omitempty"`
 | |
| }
 | |
| 
 | |
| // MetaProject is the meta information about a project returned from createmeta api
 | |
| type MetaProject struct {
 | |
| 	Expand string `json:"expand,omitempty"`
 | |
| 	Self   string `json:"self,omitempty"`
 | |
| 	Id     string `json:"id,omitempty"`
 | |
| 	Key    string `json:"key,omitempty"`
 | |
| 	Name   string `json:"name,omitempty"`
 | |
| 	// omitted avatarUrls
 | |
| 	IssueTypes []*MetaIssueType `json:"issuetypes,omitempty"`
 | |
| }
 | |
| 
 | |
| // MetaIssueType represents the different issue types a project has.
 | |
| //
 | |
| // Note: Fields is interface because this is an object which can
 | |
| // have arbitraty keys related to customfields. It is not possible to
 | |
| // expect these for a general way. This will be returning a map.
 | |
| // Further processing must be done depending on what is required.
 | |
| type MetaIssueType struct {
 | |
| 	Self        string                `json:"self,omitempty"`
 | |
| 	Id          string                `json:"id,omitempty"`
 | |
| 	Description string                `json:"description,omitempty"`
 | |
| 	IconUrl     string                `json:"iconurl,omitempty"`
 | |
| 	Name        string                `json:"name,omitempty"`
 | |
| 	Subtasks    bool                  `json:"subtask,omitempty"`
 | |
| 	Expand      string                `json:"expand,omitempty"`
 | |
| 	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"})
 | |
| }
 | |
| 
 | |
| // 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) {
 | |
| 	apiEndpoint := "rest/api/2/issue/createmeta"
 | |
| 
 | |
| 	req, err := s.client.NewRequest("GET", apiEndpoint, nil)
 | |
| 	if err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 	if options != nil {
 | |
| 		q, err := query.Values(options)
 | |
| 		if err != nil {
 | |
| 			return nil, nil, err
 | |
| 		}
 | |
| 		req.URL.RawQuery = q.Encode()
 | |
| 	}
 | |
| 
 | |
| 	meta := new(CreateMetaInfo)
 | |
| 	resp, err := s.client.Do(req, meta)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return nil, resp, err
 | |
| 	}
 | |
| 
 | |
| 	return meta, resp, nil
 | |
| }
 | |
| 
 | |
| // 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 {
 | |
| 	for _, m := range m.Projects {
 | |
| 		if strings.ToLower(m.Name) == strings.ToLower(name) {
 | |
| 			return m
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetProjectWithKey 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) GetProjectWithKey(key string) *MetaProject {
 | |
| 	for _, m := range m.Projects {
 | |
| 		if strings.ToLower(m.Key) == strings.ToLower(key) {
 | |
| 			return m
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetIssueTypeWithName returns an IssueType with name from a given MetaProject. If not found, this returns nil.
 | |
| // The comparison of the name is case insensitive
 | |
| func (p *MetaProject) GetIssueTypeWithName(name string) *MetaIssueType {
 | |
| 	for _, m := range p.IssueTypes {
 | |
| 		if strings.ToLower(m.Name) == strings.ToLower(name) {
 | |
| 			return m
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetMandatoryFields returns a map of all the required fields from the MetaIssueTypes.
 | |
| // if a field returned by the api was:
 | |
| // "customfield_10806": {
 | |
| //					"required": true,
 | |
| //					"schema": {
 | |
| //						"type": "any",
 | |
| //						"custom": "com.pyxis.greenhopper.jira:gh-epic-link",
 | |
| //						"customId": 10806
 | |
| //					},
 | |
| //					"name": "Epic Link",
 | |
| //					"hasDefaultValue": false,
 | |
| //					"operations": [
 | |
| //						"set"
 | |
| //					]
 | |
| //				}
 | |
| // the returned map would have "Epic Link" as the key and "customfield_10806" as value.
 | |
| // This choice has been made so that the it is easier to generate the create api request later.
 | |
| func (t *MetaIssueType) GetMandatoryFields() (map[string]string, error) {
 | |
| 	ret := make(map[string]string)
 | |
| 	for key := range t.Fields {
 | |
| 		required, err := t.Fields.Bool(key + "/required")
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if required {
 | |
| 			name, err := t.Fields.String(key + "/name")
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			ret[name] = key
 | |
| 		}
 | |
| 	}
 | |
| 	return ret, nil
 | |
| }
 | |
| 
 | |
| // GetAllFields returns a map of all the fields for an IssueType. This includes all required and not required.
 | |
| // The key of the returned map is what you see in the form and the value is how it is representated in the jira schema.
 | |
| func (t *MetaIssueType) GetAllFields() (map[string]string, error) {
 | |
| 	ret := make(map[string]string)
 | |
| 	for key := range t.Fields {
 | |
| 
 | |
| 		name, err := t.Fields.String(key + "/name")
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		ret[name] = key
 | |
| 	}
 | |
| 	return ret, nil
 | |
| }
 | |
| 
 | |
| // CheckCompleteAndAvailable checks if the given fields satisfies the mandatory field required to create a issue for the given type
 | |
| // And also if the given fields are available.
 | |
| func (t *MetaIssueType) CheckCompleteAndAvailable(config map[string]string) (bool, error) {
 | |
| 	mandatory, err := t.GetMandatoryFields()
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	all, err := t.GetAllFields()
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 
 | |
| 	// check templateconfig against mandatory fields
 | |
| 	for key := range mandatory {
 | |
| 		if _, okay := config[key]; !okay {
 | |
| 			var requiredFields []string
 | |
| 			for name := range mandatory {
 | |
| 				requiredFields = append(requiredFields, name)
 | |
| 			}
 | |
| 			return false, fmt.Errorf("Required field not found in provided jira.fields. Required are: %#v", requiredFields)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// check templateConfig against all fields to verify they are available
 | |
| 	for key := range config {
 | |
| 		if _, okay := all[key]; !okay {
 | |
| 			var availableFields []string
 | |
| 			for name := range all {
 | |
| 				availableFields = append(availableFields, name)
 | |
| 			}
 | |
| 			return false, fmt.Errorf("Fields in jira.fields are not available in jira. Available are: %#v", availableFields)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return true, nil
 | |
| }
 |