diff --git a/src/WorkItemMigrator/JiraExport/JiraItem.cs b/src/WorkItemMigrator/JiraExport/JiraItem.cs index f90e0a35..fe5b6e49 100644 --- a/src/WorkItemMigrator/JiraExport/JiraItem.cs +++ b/src/WorkItemMigrator/JiraExport/JiraItem.cs @@ -34,23 +34,7 @@ private static List BuildRevisions(JiraItem jiraItem, IJiraProvide { string issueKey = jiraItem.Key; var remoteIssue = jiraItem.RemoteIssue; - Dictionary fieldsTemp = ExtractFields(issueKey, remoteIssue, jiraProvider); - - // Add CustomFieldName fields, copy over all non-custom fields. - // These get removed as we loop over the changeLog, so we're left with the original Jira values by the time we reach firstRevision. - Dictionary fields = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (var field in fieldsTemp) - { - var key = GetCustomFieldName(field.Key, jiraProvider); - if (!String.IsNullOrEmpty(key)) - { - fields[key] = field.Value; - } - else - { - fields[field.Key] = field.Value; - } - } + Dictionary fields = ExtractFields(issueKey, remoteIssue, jiraProvider); List attachments = ExtractAttachments(remoteIssue.SelectTokens("$.fields.attachment[*]").Cast()) ?? new List(); List links = ExtractLinks(issueKey, remoteIssue.SelectTokens("$.fields.issuelinks[*]").Cast()) ?? new List(); @@ -332,11 +316,7 @@ private static (string, string, string) TransformFieldChange(JiraChangeItem item private static string GetCustomFieldId(string fieldName, IJiraProvider jira) { - var customField = jira.GetCustomField(fieldName); - if (customField != null) - return customField.Id; - else return null; - + return jira.GetCustomId(fieldName); } protected static string GetCustomFieldName(string fieldId, IJiraProvider jira) diff --git a/src/WorkItemMigrator/JiraExport/JiraMapper.cs b/src/WorkItemMigrator/JiraExport/JiraMapper.cs index e9993d89..08123a56 100644 --- a/src/WorkItemMigrator/JiraExport/JiraMapper.cs +++ b/src/WorkItemMigrator/JiraExport/JiraMapper.cs @@ -75,6 +75,9 @@ internal Dictionary> InitializeFieldMappings( if (item.Source != null) { var isCustomField = item.SourceType == "name"; + if (isCustomField && _jiraProvider.GetCustomId(item.Source) == null) + Logger.Log(LogLevel.Warning, $"Could not find the field id for '{item.Source}', please check the field mapping!"); + Func value; if (item.Mapping?.Values != null) @@ -248,7 +251,7 @@ internal List MapLinks(JiraRevision r) } // map epic link - LinkMapperUtils.AddRemoveSingleLink(r, links, _config.EpicLinkField, "Epic", _config); + LinkMapperUtils.AddRemoveSingleLink(r, links, _jiraProvider.GetSettings().EpicLinkField, "Epic", _config); // map parent LinkMapperUtils.AddRemoveSingleLink(r, links, "parent", "Parent", _config); @@ -375,29 +378,14 @@ private HashSet InitializeTypeMappings() private Func IfChanged(string sourceField, bool isCustomField, Func mapperFunc = null) { - // Store both the customFieldName and the sourceField as the changelog seems to only use the customFieldName, which is then passed into this function as the sourceField. - string customFieldName = ""; if (isCustomField) { - customFieldName = _jiraProvider.GetCustomId(sourceField); + sourceField = _jiraProvider.GetCustomId(sourceField) ?? sourceField; } return (r) => { - object value; - // This sourceField is often actually the customFieldName. - if (r.Fields.TryGetValue(sourceField.ToLower(), out value)) - { - if (mapperFunc != null) - { - return (true, mapperFunc((T)value)); - } - else - { - return (true, (T)value); - } - } - else if (r.Fields.TryGetValue(customFieldName.ToLower(), out value)) + if (r.Fields.TryGetValue(sourceField.ToLower(), out object value)) { if (mapperFunc != null) { diff --git a/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraItemTests.cs b/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraItemTests.cs index 61494314..223ce100 100644 --- a/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraItemTests.cs +++ b/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraItemTests.cs @@ -577,7 +577,7 @@ public void When_an_epic_link_was_removed_Then_the_result_should_be_successful() } [Test] - public void When_a_custom_field_is_added_Then_a_customfield_is_added_to_the_revision_with_name_as_key() + public void When_a_custom_field_is_added_Then_no_customfield_is_added_to_the_revision_with_name_as_key() { //Arrange var provider = _fixture.Freeze(); @@ -586,7 +586,7 @@ public void When_a_custom_field_is_added_Then_a_customfield_is_added_to_the_revi string customFieldId = _fixture.Create(); string customFieldName = _fixture.Create(); - var fields = JObject.Parse(@"{'issuetype': {'name': 'Story'},'" + customFieldId + @"': {'name':'SomeValue'}}"); + var fields = JObject.Parse(@"{'issuetype': {'name': 'Story'},'" + customFieldId + @"': {'name':'SomeValue', 'key':'" + customFieldId + "'}}"); var renderedFields = new JObject(); var changelog = new List(); @@ -604,10 +604,7 @@ public void When_a_custom_field_is_added_Then_a_customfield_is_added_to_the_revi var jiraSettings = createJiraSettings(); provider.GetSettings().ReturnsForAnyArgs(jiraSettings); - RemoteField remoteField = new RemoteField(); - remoteField.id = customFieldId; - remoteField.name = customFieldName; - CustomField customField = new CustomField(remoteField); + CustomField customField = null; provider.GetCustomField(default).ReturnsForAnyArgs(customField); @@ -618,13 +615,12 @@ public void When_a_custom_field_is_added_Then_a_customfield_is_added_to_the_revi Assert.Multiple(() => { Assert.AreEqual(1, jiraItem.Revisions.Count); - Assert.IsFalse(jiraItem.Revisions[0].Fields.Any(f => f.Key == customFieldId)); - Assert.IsTrue(jiraItem.Revisions[0].Fields.Any(f => f.Key == customFieldName)); + Assert.IsFalse(jiraItem.Revisions[0].Fields.Any(f => f.Key == customFieldName)); }); } [Test] - public void When_a_custom_field_is_added_Then_no_customfield_is_added_to_the_revision_with_name_as_key() + public void When_an_custom_field_is_changed_Then_it_should_have_the_previous_value_in_the_initial_revision() { //Arrange var provider = _fixture.Freeze(); @@ -632,11 +628,24 @@ public void When_a_custom_field_is_added_Then_no_customfield_is_added_to_the_rev string issueKey = _fixture.Create(); string customFieldId = _fixture.Create(); string customFieldName = _fixture.Create(); + string customFieldPreviousValue = _fixture.Create(); + string customFieldNewValue = _fixture.Create(); - var fields = JObject.Parse(@"{'issuetype': {'name': 'Story'},'" + customFieldId + @"': {'name':'SomeValue', 'key':'" + customFieldId + "'}}"); + var fields = JObject.Parse(@"{'issuetype': {'name': 'Story'},'" + customFieldId + @"': '" + customFieldNewValue + @"', 'key':'" + issueKey + "'}"); var renderedFields = new JObject(); - var changelog = new List(); + var changelog = new List() + { + new HistoryItem() + { + Field = customFieldName, + FieldType = "custom", + From = customFieldPreviousValue, + FromString = customFieldPreviousValue, + To = customFieldNewValue, + ToString = customFieldNewValue + }.ToJObject() + }; JObject remoteIssue = new JObject { @@ -651,9 +660,61 @@ public void When_a_custom_field_is_added_Then_no_customfield_is_added_to_the_rev var jiraSettings = createJiraSettings(); provider.GetSettings().ReturnsForAnyArgs(jiraSettings); - CustomField customField = null; + provider.GetCustomId(customFieldName).Returns(customFieldId); - provider.GetCustomField(default).ReturnsForAnyArgs(customField); + //Act + var jiraItem = JiraItem.CreateFromRest(issueKey, provider); + + //Assert + Assert.Multiple(() => + { + Assert.AreEqual(2, jiraItem.Revisions.Count); + Assert.IsTrue(jiraItem.Revisions[0].Fields.ContainsKey(customFieldId)); + Assert.AreEqual(customFieldPreviousValue, jiraItem.Revisions[0].Fields[customFieldId]); + Assert.IsTrue(jiraItem.Revisions[1].Fields.ContainsKey(customFieldId)); + Assert.AreEqual(customFieldNewValue, jiraItem.Revisions[1].Fields[customFieldId]); + }); + } + + [Test] + public void When_an_custom_field_is_added_and_changed_later_Then_it_should_not_be_in_the_initial_revision() + { + //Arrange + var provider = _fixture.Freeze(); + long issueId = _fixture.Create(); + string issueKey = _fixture.Create(); + string customFieldId = _fixture.Create(); + string customFieldName = _fixture.Create(); + string customFieldNewValue = _fixture.Create(); + + var fields = JObject.Parse(@"{'issuetype': {'name': 'Story'},'" + customFieldId + @"': '" + customFieldNewValue + @"', 'key':'" + issueKey + "'}"); + var renderedFields = new JObject(); + + var changelog = new List() + { + new HistoryItem() + { + Field = customFieldName, + FieldType = "custom", + To = customFieldNewValue, + ToString = customFieldNewValue + }.ToJObject() + }; + + JObject remoteIssue = new JObject + { + { "id", issueId }, + { "key", issueKey }, + { "fields", fields }, + { "renderedFields", renderedFields } + }; + + provider.DownloadIssue(default).ReturnsForAnyArgs(remoteIssue); + provider.DownloadChangelog(default).ReturnsForAnyArgs(changelog); + var jiraSettings = createJiraSettings(); + provider.GetSettings().ReturnsForAnyArgs(jiraSettings); + + provider.GetCustomId(customFieldName).Returns(customFieldId); //Act var jiraItem = JiraItem.CreateFromRest(issueKey, provider); @@ -661,8 +722,12 @@ public void When_a_custom_field_is_added_Then_no_customfield_is_added_to_the_rev //Assert Assert.Multiple(() => { - Assert.AreEqual(1, jiraItem.Revisions.Count); - Assert.IsFalse(jiraItem.Revisions[0].Fields.Any(f => f.Key == customFieldName)); + Assert.AreEqual(2, jiraItem.Revisions.Count); + Assert.IsFalse(jiraItem.Revisions[0].Fields.ContainsKey(customFieldId)); + Assert.IsFalse(jiraItem.Revisions[0].Fields.ContainsKey(customFieldName)); + Assert.IsTrue(jiraItem.Revisions[1].Fields.ContainsKey(customFieldId)); + Assert.IsFalse(jiraItem.Revisions[1].Fields.ContainsKey(customFieldName)); + Assert.AreEqual(customFieldNewValue, jiraItem.Revisions[1].Fields[customFieldId]); }); } diff --git a/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraMapperTests.cs b/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraMapperTests.cs index 479e431e..3ab9aa52 100644 --- a/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraMapperTests.cs +++ b/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraMapperTests.cs @@ -73,7 +73,7 @@ public void When_calling_map_on_an_issue_with_an_epic_link_and_a_parent_Then_two var fields = JObject.Parse(@"{ 'issuetype': {'name': 'Story'}, - 'Epic Link': 'EpicKey' + 'EpicLinkField': 'EpicKey' }"); var renderedFields = JObject.Parse("{ 'custom_field_name': 'SomeValue', 'description': 'RenderedDescription' }"); @@ -88,7 +88,7 @@ public void When_calling_map_on_an_issue_with_an_epic_link_and_a_parent_Then_two new HistoryItem() { Id = 1, - Field = "parent", + Field = "Parent", FieldType = "jira", To = parentId, ToString = parentKey @@ -273,8 +273,6 @@ private JiraMapper createJiraMapper() repositoryMap.Repositories.Add(repository); cjson.RepositoryMap = repositoryMap; - cjson.EpicLinkField = "Epic Link"; - JiraMapper sut = new JiraMapper(provider, cjson); return sut;