From 1f368f8fe0f509c40625c76f9c3ef753927be677 Mon Sep 17 00:00:00 2001 From: Bidesh Thapaliya Date: Wed, 5 Oct 2016 18:04:48 +0200 Subject: [PATCH] Adds method to init issue with meta and fieldConfig. Adds related tests --- issue.go | 73 +++++++++++++ issue_test.go | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++ metaissue.go | 37 +++++++ 3 files changed, 406 insertions(+) diff --git a/issue.go b/issue.go index 5e98fda..c3a00ec 100644 --- a/issue.go +++ b/issue.go @@ -657,3 +657,76 @@ func (s *IssueService) DoTransition(ticketID, transitionID string) (*Response, e return resp, nil } + +// 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": + // TODO format the value into proper jira date string + 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 + + // maybe do unmarshall and marshall so that the real fields are set in issue + return issue, nil +} diff --git a/issue_test.go b/issue_test.go index 46dbff6..0333418 100644 --- a/issue_test.go +++ b/issue_test.go @@ -601,3 +601,299 @@ func TestIssueFields_MarshalJSON_Success(t *testing.T) { t.Errorf("Recieved object different from expected") } } + +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) + } +} + +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) + } +} + +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 TestInitIssueWithMetaAndFields_UserValueType(t *testing.T) { + metaProject := MetaProject{ + Name: "Engineering - Dept", + Id: "ENG", + } + + fields := tcontainer.NewMarshalMap() + fields["assignee"] = map[string]interface{}{ + "name": "Assignee", + "schema": map[string]interface{}{ + "type": "user", + }, + } + + metaIssueType := MetaIssueType{ + Fields: fields, + } + + expectedAssignee := "jdoe" + fieldConfig := map[string]string{ + "Assignee": expectedAssignee, + } + + issue, err := InitIssueWithMetaAndFields(&metaProject, &metaIssueType, fieldConfig) + if err != nil { + t.Errorf("Expected nil error, recieved %s", err) + } + + a, _ := issue.Fields.Unknowns.Value("assignee") + gotAssignee := a.(User).Name + + if gotAssignee != expectedAssignee { + t.Errorf("Expected %s recieved %s", expectedAssignee, gotAssignee) + } +} + +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_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_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") + } + +} diff --git a/metaissue.go b/metaissue.go index c57f12f..0d5c73b 100644 --- a/metaissue.go +++ b/metaissue.go @@ -143,3 +143,40 @@ func (t *MetaIssueType) GetAllFields() (map[string]string, error) { } 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 +}