// 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. // * fieldsConfig is a key->value pair where key represents the name of the field as seen in the UI // And value is the string value for that particular key. // Note: This method doesn't verify that the fieldsConfig is complete with mandatory fields. The fieldsConfig is // supposed to be already verified with MetaIssueType.CheckCompleteAndAvailable. It will however return // error if the key is not found. // All values will be packed into Unknowns. This is much convenient. If the struct fields needs to be // configured as well, marshalling and unmarshalling will set the proper fields. func InitIssueWithMetaAndFields(metaProject *MetaProject, metaIssuetype *MetaIssueType, fieldsConfig map[string]string) (*Issue, error) { issue := new(Issue) issueFields := new(IssueFields) issueFields.Unknowns = tcontainer.NewMarshalMap() // map the field names the User presented to jira's internal key allFields, _ := metaIssuetype.GetAllFields() for key, value := range fieldsConfig { jiraKey, found := allFields[key] if !found { return nil, fmt.Errorf("Key %s is not found in the list of fields.", key) } valueType, err := metaIssuetype.Fields.String(jiraKey + "/schema/type") if err != nil { return nil, err } switch valueType { case "array": elemType, err := metaIssuetype.Fields.String(jiraKey + "/schema/items") if err != nil { return nil, err } switch elemType { case "component": issueFields.Unknowns[jiraKey] = []Component{Component{Name: value}} default: issueFields.Unknowns[jiraKey] = []string{value} } case "string": issueFields.Unknowns[jiraKey] = value case "date": issueFields.Unknowns[jiraKey] = value case "any": // Treat any as string issueFields.Unknowns[jiraKey] = value case "project": issueFields.Unknowns[jiraKey] = Project{ Name: metaProject.Name, ID: metaProject.Id, } case "priority": issueFields.Unknowns[jiraKey] = Priority{Name: value} case "user": issueFields.Unknowns[jiraKey] = User{ Name: value, } case "issuetype": issueFields.Unknowns[jiraKey] = IssueType{ Name: value, } default: return nil, fmt.Errorf("Unknown issue type encountered: %s for %s", valueType, key) } } issue.Fields = issueFields return issue, nil }
func TestInitIssueWithmetaAndFields_FailureWithUnknownValueType(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["issuetype"] = map[string]interface{}{ "name": "Issue type", "schema": map[string]interface{}{ "type": "randomType", }, } metaIssueType := MetaIssueType{ Fields: fields, } fieldConfig := map[string]string{ "Issue tyoe": "sometype", } _, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err == nil { t.Error("Expected non nil error, recieved nil") } }
func TestInitIssueWithMetaAndFields_PriorityValueType(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["priority"] = map[string]interface{}{ "name": "Priority", "schema": map[string]interface{}{ "type": "priority", }, } metaIssueType := MetaIssueType{ Fields: fields, } expectedPriority := "Normal" fieldConfig := map[string]string{ "Priority": expectedPriority, } issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err != nil { t.Errorf("Expected nil error, recieved %s", err) } a, _ := issue.Fields.Unknowns.Value("priority") gotPriority := a.(Priority).Name if gotPriority != expectedPriority { t.Errorf("Expected %s recieved %s", expectedPriority, gotPriority) } }
func TestInitIssueWithMetaAndFields_IssuetypeValueType(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["issuetype"] = map[string]interface{}{ "name": "Issue type", "schema": map[string]interface{}{ "type": "issuetype", }, } metaIssueType := MetaIssueType{ Fields: fields, } expectedIssuetype := "Bug" fieldConfig := map[string]string{ "Issue type": expectedIssuetype, } issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err != nil { t.Errorf("Expected nil error, recieved %s", err) } a, _ := issue.Fields.Unknowns.Value("issuetype") gotIssuetype := a.(IssueType).Name if gotIssuetype != expectedIssuetype { t.Errorf("Expected %s recieved %s", expectedIssuetype, gotIssuetype) } }
func TestInitIssueWithMetaAndFields_ProjectValueType(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["project"] = map[string]interface{}{ "name": "Project", "schema": map[string]interface{}{ "type": "project", }, } metaIssueType := MetaIssueType{ Fields: fields, } setProject := "somewhere" fieldConfig := map[string]string{ "Project": setProject, } issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err != nil { t.Errorf("Expected nil error, recieved %s", err) } a, _ := issue.Fields.Unknowns.Value("project") gotProject := a.(Project).Name if gotProject != metaProject.Name { t.Errorf("Expected %s recieved %s", metaProject.Name, gotProject) } }
func TestInitIssueWithMetaAndFields_ArrayValueType(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["component"] = map[string]interface{}{ "name": "Component/s", "schema": map[string]interface{}{ "type": "array", "items": "component", }, } metaIssueType := MetaIssueType{ Fields: fields, } expectedComponent := "Jira automation" fieldConfig := map[string]string{ "Component/s": expectedComponent, } issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err != nil { t.Errorf("Expected nil error, recieved %s", err) } c, isArray := issue.Fields.Unknowns["component"].([]Component) if isArray == false { t.Error("Expected array, non array object recieved") } if len(c) != 1 { t.Errorf("Expected recieved array to be of length 1. Got %d", len(c)) } gotComponent := c[0].Name if err != nil { t.Errorf("Expected err to be nil, recieved %s", err) } if gotComponent != expectedComponent { t.Errorf("Expected %s recieved %s", expectedComponent, gotComponent) } }
// UnmarshalJSON is a custom JSON marshal function for the IssueFields structs. // It handles JIRA custom fields and maps those from / to "Unknowns" key. func (i *IssueFields) UnmarshalJSON(data []byte) error { // Do the normal unmarshalling first // Details for this way: http://choly.ca/post/go-json-marshalling/ type Alias IssueFields aux := &struct { *Alias }{ Alias: (*Alias)(i), } if err := json.Unmarshal(data, &aux); err != nil { return err } totalMap := tcontainer.NewMarshalMap() err := json.Unmarshal(data, &totalMap) if err != nil { return err } t := reflect.TypeOf(*i) for i := 0; i < t.NumField(); i++ { field := t.Field(i) tagDetail := field.Tag.Get("json") if tagDetail == "" { // ignore if there are no tags continue } options := strings.Split(tagDetail, ",") if len(options) == 0 { return fmt.Errorf("No tags options found for %s", field.Name) } // the first one is the json tag key := options[0] if _, okay := totalMap.Value(key); okay { delete(totalMap, key) } } i = (*IssueFields)(aux.Alias) // all the tags found in the struct were removed. Whatever is left are unknowns to struct i.Unknowns = totalMap return nil }
func TestInitIssueWithMetaAndFields_DateValueType(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["created"] = map[string]interface{}{ "name": "Created", "schema": map[string]interface{}{ "type": "date", }, } metaIssueType := MetaIssueType{ Fields: fields, } expectedCreated := "19 oct 2012" fieldConfig := map[string]string{ "Created": expectedCreated, } issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err != nil { t.Errorf("Expected nil error, recieved %s", err) } gotCreated, err := issue.Fields.Unknowns.String("created") if err != nil { t.Errorf("Expected err to be nil, recieved %s", err) } if gotCreated != expectedCreated { t.Errorf("Expected %s recieved %s", expectedCreated, gotCreated) } }
func TestIssueFields_MarshalJSON_OmitsEmptyFields(t *testing.T) { i := &IssueFields{ Description: "blahblah", Type: IssueType{ Name: "Story", }, Labels: []string{"aws-docker"}, } rawdata, err := json.Marshal(i) if err != nil { t.Errorf("Expected nil err, recieved %s", err) } // convert json to map and see if unset keys are there issuef := tcontainer.NewMarshalMap() err = json.Unmarshal(rawdata, &issuef) if err != nil { t.Errorf("Expected nil err, received %s", err) } _, err = issuef.Int("issuetype/avatarId") if err == nil { t.Error("Expected non nil error, recieved nil") } // verify that the field that should be there, is. name, err := issuef.String("issuetype/name") if err != nil { t.Errorf("Expected nil err, received %s", err) } if name != "Story" { t.Errorf("Expected Story, received %s", name) } }
func TestInitIssueWithMetaAndFields_Success(t *testing.T) { metaProject := MetaProject{ Name: "Engineering - Dept", Id: "ENG", } fields := tcontainer.NewMarshalMap() fields["summary"] = map[string]interface{}{ "name": "Summary", "schema": map[string]interface{}{ "type": "string", }, } metaIssueType := MetaIssueType{ Fields: fields, } expectedSummary := "Issue Summary" fieldConfig := map[string]string{ "Summary": "Issue Summary", } issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) if err != nil { t.Errorf("Expected nil error, recieved %s", err) } gotSummary, found := issue.Fields.Unknowns["summary"] if !found { t.Errorf("Expected summary to be set in issue. Not set.") } if gotSummary != expectedSummary { t.Errorf("Expected %s recieved %s", expectedSummary, gotSummary) } }