From 45d18eddaf1d47943aa078e5566baca251fda9cd Mon Sep 17 00:00:00 2001
From: mammabear123 <127075115+mammabear123@users.noreply.github.com>
Date: Thu, 7 Dec 2023 13:23:44 +0800
Subject: [PATCH 1/4] Determine which is the last revision and signify this to
ImportRevision.
---
src/WorkItemMigrator/WorkItemImport/Agent.cs | 2 +-
src/WorkItemMigrator/WorkItemImport/ExecutionPlan.cs | 4 +++-
.../WorkItemImport/ExecutionPlanBuilder.cs | 8 ++++++++
src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs | 2 +-
src/WorkItemMigrator/WorkItemImport/RevisionReference.cs | 2 ++
5 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/WorkItemMigrator/WorkItemImport/Agent.cs b/src/WorkItemMigrator/WorkItemImport/Agent.cs
index 4bf74883..ad70e36d 100644
--- a/src/WorkItemMigrator/WorkItemImport/Agent.cs
+++ b/src/WorkItemMigrator/WorkItemImport/Agent.cs
@@ -57,7 +57,7 @@ public WorkItem CreateWorkItem(string type, bool suppressNotifications, DateTime
return _witClientUtils.CreateWorkItem(type, suppressNotifications, createdDate, createdBy);
}
- public bool ImportRevision(WiRevision rev, WorkItem wi, Settings settings)
+ public bool ImportRevision(WiRevision rev, WorkItem wi, Settings settings, bool isFinalRevision)
{
var incomplete = false;
try
diff --git a/src/WorkItemMigrator/WorkItemImport/ExecutionPlan.cs b/src/WorkItemMigrator/WorkItemImport/ExecutionPlan.cs
index 43b2b7c6..001c7f57 100644
--- a/src/WorkItemMigrator/WorkItemImport/ExecutionPlan.cs
+++ b/src/WorkItemMigrator/WorkItemImport/ExecutionPlan.cs
@@ -12,6 +12,8 @@ public class ExecutionItem
public int WiId { get; set; } = -1;
public WiRevision Revision { get; set; }
public string WiType { get; internal set; }
+ /// Is this the final revision for the work item?
+ public bool IsFinal { get; set; } = false;
public override string ToString()
{
@@ -34,7 +36,7 @@ private ExecutionItem TransformToExecutionItem(RevisionReference revRef)
var item = _context.GetItem(revRef.OriginId);
var rev = item.Revisions[revRef.RevIndex];
rev.Time = revRef.Time;
- return new ExecutionItem() { OriginId = item.OriginId, WiId = item.WiId, WiType = item.Type, Revision = rev };
+ return new ExecutionItem() { OriginId = item.OriginId, WiId = item.WiId, WiType = item.Type, Revision = rev, IsFinal = revRef.IsFinal };
}
public bool TryPop(out ExecutionItem nextItem)
diff --git a/src/WorkItemMigrator/WorkItemImport/ExecutionPlanBuilder.cs b/src/WorkItemMigrator/WorkItemImport/ExecutionPlanBuilder.cs
index dee862dd..dc2bc9eb 100644
--- a/src/WorkItemMigrator/WorkItemImport/ExecutionPlanBuilder.cs
+++ b/src/WorkItemMigrator/WorkItemImport/ExecutionPlanBuilder.cs
@@ -34,11 +34,19 @@ private IEnumerable BuildExecutionPlanFromDir()
foreach (var wi in _context.EnumerateAllItems())
{
Logger.Log(LogLevel.Debug, $"Analyzing item '{wi.OriginId}'.");
+ RevisionReference lastRevision = null;
foreach (var rev in wi.Revisions)
{
var revRef = new RevisionReference() { OriginId = wi.OriginId, RevIndex = rev.Index, Time = rev.Time };
+ lastRevision = revRef;
actionPlan.Add(revRef);
}
+
+ if (lastRevision != null)
+ {
+ // mark the last revision as final.
+ lastRevision.IsFinal = true;
+ }
}
actionPlan.Sort();
diff --git a/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs b/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs
index f5833cb6..d48abf81 100644
--- a/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs
+++ b/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs
@@ -141,7 +141,7 @@ private bool ExecuteMigration(CommandOption token, CommandOption url, CommandOpt
continue;
}
- agent.ImportRevision(executionItem.Revision, wi, settings);
+ agent.ImportRevision(executionItem.Revision, wi, settings, executionItem.IsFinal);
// Artifical wait (optional) to avoid throttling for ADO Services
if (config.SleepTimeBetweenRevisionImportMilliseconds > 0)
diff --git a/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs b/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs
index 112728ac..ef2cfeb9 100644
--- a/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs
+++ b/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs
@@ -7,6 +7,8 @@ public sealed class RevisionReference : IComparable, IEquatab
public string OriginId { get; set; }
public int RevIndex { get; set; }
public DateTime Time { get; set; }
+ /// Is this the final/latest revision for the work item?
+ public bool IsFinal { get; set; } = false;
public int CompareTo(RevisionReference other)
{
From 241c8be73c64a86280f9b8b1fefdb3935a91a3f4 Mon Sep 17 00:00:00 2001
From: mammabear123 <127075115+mammabear123@users.noreply.github.com>
Date: Tue, 12 Dec 2023 21:29:07 +0800
Subject: [PATCH 2/4] Add BoardColumnCollector and write BoardColumn into final
revision.
---
.../WorkItemImport/BoardColumnCollector.cs | 92 ++++++
.../WorkItemImport/ImportCommandLine.cs | 6 +-
.../WitClient/WitClientUtils.cs | 32 ++-
.../WorkItemImport/wi-import.csproj | 1 +
.../BoardColumnCollectorTests.cs | 269 ++++++++++++++++++
5 files changed, 396 insertions(+), 4 deletions(-)
create mode 100644 src/WorkItemMigrator/WorkItemImport/BoardColumnCollector.cs
create mode 100644 src/WorkItemMigrator/tests/Migration.Wi-Import.Tests/BoardColumnCollectorTests.cs
diff --git a/src/WorkItemMigrator/WorkItemImport/BoardColumnCollector.cs b/src/WorkItemMigrator/WorkItemImport/BoardColumnCollector.cs
new file mode 100644
index 00000000..6655fbd2
--- /dev/null
+++ b/src/WorkItemMigrator/WorkItemImport/BoardColumnCollector.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Migration.WIContract;
+
+namespace WorkItemImport
+{
+ ///
+ /// Implementations of this interface will track the value of a field over multiple revisions for each item. They can
+ /// then be queried for the 'current' value of the field as per the latest revision they have seen the a field in.
+ ///
+ /// The type used when storing and retrieving the field's value.
+ public interface IFieldCollector
+ {
+ ///
+ /// Collects the field values in a similar way to but also tests . For non-final
+ /// revisions, the collected fields are also removed from the Fields array. For final revisions, adds or updates
+ /// the Field to contain the latest value of each collected field (whether collected from this revision or a previous one).
+ /// Usually implemented as a combination of and
+ ///
+ /// The execution item containing the revision to process.
+ /// It is acceptable for a revision to not contain a value for the field(s) of interest.
+ void ProcessFields(ExecutionPlan.ExecutionItem executionItem);
+
+ ///
+ /// Return the 'current' value collected for the field(s) as per the latest revision of the given work item (that specified a value for this field).
+ ///
+ ///
+ ///
+ T GetCurrentValue(string workItemId);
+
+ ///
+ /// Collect field value(s) from the given revision, updating the internal collection with the latest value(s).
+ /// The revision provided in each call is considered to overwrite value(s) collected during previous calls.
+ /// This method does not modify the revision - unlike .
+ ///
+ /// The work item revision to collect field value(s) from.
+ /// It is acceptable for a revision to not contain a value for the field(s) of interest.
+ void CollectValues(WiRevision revision);
+ }
+
+ ///
+ /// Collects System.BoardColumn values from each revision in order to provide the final value for the last revision.
+ /// Expected usage is to call ProcessFields on each revision, which will cause BoardColumn to be removed from all revisions except
+ /// the last, and the final value to be updated/inserted into the BoardColumn field of the final revision.
+ ///
+ public class BoardColumnCollector : IFieldCollector
+ {
+ private readonly Dictionary _collection = new Dictionary();
+
+ ///
+ public void CollectValues(WiRevision revision)
+ {
+ var boardColumn = revision?.Fields?.FirstOrDefault(f => f.ReferenceName == WiFieldReference.BoardColumn)?.Value as string;
+ if (!string.IsNullOrEmpty(boardColumn))
+ {
+ _collection[revision.ParentOriginId] = boardColumn;
+ }
+ }
+
+ ///
+ public string GetCurrentValue(string workItemId)
+ {
+ return _collection.TryGetValue(workItemId, out var value) ? value : null;
+ }
+
+ ///
+ /// Collects the BoardColumn value and removes the field. Except in the final revision the field is explicitly inserted with the latest value.
+ ///
+ /// The execution item containing the revision to process.
+ ///
+ public void ProcessFields(ExecutionPlan.ExecutionItem executionItem)
+ {
+ CollectValues(executionItem.Revision);
+ if (executionItem.IsFinal)
+ {
+ var boardColumnValue = GetCurrentValue(executionItem.OriginId);
+ if (!string.IsNullOrWhiteSpace(boardColumnValue))
+ {
+ executionItem.Revision.Fields.RemoveAll(i => i.ReferenceName == WiFieldReference.BoardColumn);
+ executionItem.Revision.Fields.Add(new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = boardColumnValue });
+ }
+ }
+ else
+ {
+ executionItem.Revision.Fields.RemoveAll(f => f.ReferenceName == WiFieldReference.BoardColumn);
+ }
+ }
+ }
+}
diff --git a/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs b/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs
index d48abf81..ced435f9 100644
--- a/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs
+++ b/src/WorkItemMigrator/WorkItemImport/ImportCommandLine.cs
@@ -106,6 +106,7 @@ private bool ExecuteMigration(CommandOption token, CommandOption url, CommandOpt
var executionBuilder = new ExecutionPlanBuilder(context);
var plan = executionBuilder.BuildExecutionPlan();
+ var boardColumnCollector = new BoardColumnCollector();
itemCount = plan.ReferenceQueue.AsEnumerable().Select(x => x.OriginId).Distinct().Count();
revisionCount = plan.ReferenceQueue.Count;
@@ -132,6 +133,8 @@ private bool ExecuteMigration(CommandOption token, CommandOption url, CommandOpt
importedItems++;
+ boardColumnCollector.ProcessFields(executionItem);
+
if (config.IgnoreEmptyRevisions &&
executionItem.Revision.Fields.Count == 0 &&
executionItem.Revision.Links.Count == 0 &&
@@ -143,7 +146,7 @@ private bool ExecuteMigration(CommandOption token, CommandOption url, CommandOpt
agent.ImportRevision(executionItem.Revision, wi, settings, executionItem.IsFinal);
- // Artifical wait (optional) to avoid throttling for ADO Services
+ // Artificial wait (optional) to avoid throttling for ADO Services
if (config.SleepTimeBetweenRevisionImportMilliseconds > 0)
{
Thread.Sleep(config.SleepTimeBetweenRevisionImportMilliseconds);
@@ -184,6 +187,7 @@ private bool ExecuteMigration(CommandOption token, CommandOption url, CommandOpt
return succeeded;
}
+
private static void BeginSession(string configFile, ConfigJson config, bool force, Agent agent, int itemsCount, int revisionCount)
{
var toolVersion = VersionInfo.GetVersionInfo();
diff --git a/src/WorkItemMigrator/WorkItemImport/WitClient/WitClientUtils.cs b/src/WorkItemMigrator/WorkItemImport/WitClient/WitClientUtils.cs
index 219ca303..ace98264 100644
--- a/src/WorkItemMigrator/WorkItemImport/WitClient/WitClientUtils.cs
+++ b/src/WorkItemMigrator/WorkItemImport/WitClient/WitClientUtils.cs
@@ -1,8 +1,10 @@
-using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
+using Microsoft.TeamFoundation.Work.WebApi;
+using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using Migration.Common;
+using Migration.Common.Config;
using Migration.Common.Log;
using Migration.WIContract;
using System;
@@ -625,20 +627,44 @@ public void SaveWorkItemFields(WorkItem wi, Settings settings)
{
throw new ArgumentException(nameof(wi));
}
+
+ if (wi.Fields.TryGetValue(WiFieldReference.BoardColumn, out var value))
+ {
+ wi.Fields.Remove(WiFieldReference.BoardColumn); // the API refuses to update this field directly
+ var itemType = wi.Fields[WiFieldReference.WorkItemType]?.ToString(); // used for logging
+ var kanbanField = wi.Fields.Keys.FirstOrDefault(k => k.EndsWith("_Kanban.Column")); // kanban field is the real board-column field
+
+ if (wi.Rev == 0)
+ {
+ Logger.Log(LogLevel.Warning, $"Work Item {wi.Id}, rev {wi.Rev} - BoardColumn can not be set to '{value}' because " +
+ $"items with only one revision are not supported by this feature.");
+ }
+ else if (string.IsNullOrWhiteSpace(kanbanField))
+ {
+ Logger.Log(LogLevel.Warning, $"Work Item {wi.Id}, rev {wi.Rev} - BoardColumn can not be set to '{value}' because " +
+ $"items of type '{itemType}' are not supported by this feature.");
+ }
+ else
+ {
+ Logger.Log(LogLevel.Debug, $"Work Item {wi.Id}, rev {wi.Rev} - Setting BoardColumn to '{value}'.");
+ wi.Fields[kanbanField] = value;
+ }
+ }
// Build json patch document from fields
JsonPatchDocument patchDocument = new JsonPatchDocument();
foreach (string key in wi.Fields.Keys)
{
if (new string[] {
- WiFieldReference.BoardColumn,
WiFieldReference.BoardColumnDone,
WiFieldReference.BoardLane,
}.Contains(key))
+ {
+ Logger.Log(LogLevel.Debug, $"Work Item {wi.Id} importing field {key} is not supported.");
continue;
+ }
object val = wi.Fields[key];
-
if (val == null || val.ToString() == "")
{
patchDocument.Add(
diff --git a/src/WorkItemMigrator/WorkItemImport/wi-import.csproj b/src/WorkItemMigrator/WorkItemImport/wi-import.csproj
index c11577de..f099b797 100644
--- a/src/WorkItemMigrator/WorkItemImport/wi-import.csproj
+++ b/src/WorkItemMigrator/WorkItemImport/wi-import.csproj
@@ -178,6 +178,7 @@
+
diff --git a/src/WorkItemMigrator/tests/Migration.Wi-Import.Tests/BoardColumnCollectorTests.cs b/src/WorkItemMigrator/tests/Migration.Wi-Import.Tests/BoardColumnCollectorTests.cs
new file mode 100644
index 00000000..de81ab7e
--- /dev/null
+++ b/src/WorkItemMigrator/tests/Migration.Wi-Import.Tests/BoardColumnCollectorTests.cs
@@ -0,0 +1,269 @@
+using Migration.WIContract;
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Linq;
+using WorkItemImport;
+
+
+namespace Migration.Wi_Import.Tests
+{
+ [TestFixture]
+ public class BoardColumnCollectorTests
+ {
+ private BoardColumnCollector _boardColumnCollector;
+
+ [SetUp]
+ public void Setup()
+ {
+ _boardColumnCollector = new BoardColumnCollector();
+ }
+
+ [Test]
+ public void ProcessFields_WithFinalRevision_AddsLatestBoardColumnValueToRevisionFields()
+ {
+ // Arrange
+ var executionItem1 = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "To Do" }
+ }
+ },
+ OriginId = "1",
+ IsFinal = false
+ };
+ var executionItem2 = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "Second Value" }
+ }
+ },
+ OriginId = "1",
+ IsFinal = true
+ };
+
+ // Act
+ _boardColumnCollector.ProcessFields(executionItem1);
+ _boardColumnCollector.ProcessFields(executionItem2);
+
+ // Assert
+ var boardColumnField = executionItem2.Revision.Fields.FirstOrDefault(f => f.ReferenceName == WiFieldReference.BoardColumn);
+ Assert.IsNotNull(boardColumnField);
+ Assert.AreEqual("Second Value", boardColumnField.Value);
+ }
+
+ [Test]
+ public void ProcessFields_WithNonFinalRevision_DoesNotAddBoardColumnFieldFromRevisionFields()
+ {
+ // Arrange
+ var executionItem = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.Title, Value = "Test Title" },
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "To Do" }
+ },
+ },
+ OriginId = "1",
+ IsFinal = false
+ };
+
+ // Act
+ _boardColumnCollector.ProcessFields(executionItem);
+
+ // Assert
+ var boardColumnField = executionItem.Revision.Fields.FirstOrDefault(f => f.ReferenceName == WiFieldReference.BoardColumn);
+ Assert.IsNull(boardColumnField);
+
+ }
+
+ [Test]
+ public void ProcessFields_MultipleCallsWithDifferentBoardColumnValues_ReturnsCorrectCurrentValue()
+ {
+ // Arrange
+ var firstValue = "ValueOne";
+ var secondValue = "ValueTwo";
+
+ var collector = new BoardColumnCollector();
+ var executionItem1 = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = firstValue }
+ }
+ },
+ IsFinal = false,
+ OriginId = "1"
+ };
+ var executionItem2 = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = secondValue }
+ }
+ },
+ IsFinal = false,
+ OriginId = "1"
+ };
+
+ // Act
+ collector.ProcessFields(executionItem1);
+ collector.ProcessFields(executionItem2);
+ var latestValue = collector.GetCurrentValue("1");
+
+ // Assert
+ Assert.AreEqual(secondValue, latestValue);
+
+ }
+
+ [Test]
+ public void ProcessFields_FinalRevisionDoesNotHaveBoardColumn_RetainsPreviousValueAndSetsInTheFinalRevision()
+ {
+ // Arrange
+ var executionItem1 = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "To Do" },
+ new WiField { ReferenceName = WiFieldReference.Title, Value = "First Item" }
+ }
+ },
+ OriginId = "1",
+ IsFinal = false
+ };
+ var executionItemWithoutBoardColumn = new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.Title, Value = "Second Item" }
+ }
+ },
+ IsFinal = true,
+ OriginId = "1"
+ };
+
+ // Act
+ _boardColumnCollector.ProcessFields(executionItem1);
+ _boardColumnCollector.ProcessFields(executionItemWithoutBoardColumn);
+
+ // Assert
+ var boardColumnField = executionItem1.Revision.Fields.FirstOrDefault(f => f.ReferenceName == WiFieldReference.BoardColumn);
+ Assert.IsNull(boardColumnField);
+ boardColumnField = executionItemWithoutBoardColumn.Revision.Fields.FirstOrDefault(f => f.ReferenceName == WiFieldReference.BoardColumn);
+ Assert.IsNotNull(boardColumnField);
+ }
+
+ [Test]
+ public void GetCurrentValue_WithExistingWorkItemId_ReturnsLatestBoardColumnValue()
+ {
+ // Arrange
+ _boardColumnCollector.ProcessFields(new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "To Do" }
+ }
+ },
+ OriginId = "1",
+ IsFinal = true
+ });
+
+ // Act
+ var currentValue = _boardColumnCollector.GetCurrentValue("1");
+
+ // Assert
+ Assert.AreEqual("To Do", currentValue);
+ }
+
+ [Test]
+ public void GetCurrentValue_WithNonExistingWorkItemId_ReturnsNull()
+ {
+ // Arrange
+ _boardColumnCollector.ProcessFields(new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "To Do" }
+ }
+ },
+ OriginId = "1",
+ IsFinal = true
+ });
+
+ // Act
+ var currentValue = _boardColumnCollector.GetCurrentValue("2");
+
+ // Assert
+ Assert.IsNull(currentValue);
+ }
+
+ [Test]
+ public void GetCurrentValue_WithWorkItemThatHasNoBoardColumnValue_ReturnsNull()
+ {
+ // Arrange
+ _boardColumnCollector.ProcessFields(new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "1",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.BoardColumn, Value = "To Do" }
+ }
+ },
+ OriginId = "1",
+ IsFinal = true
+ });
+ _boardColumnCollector.ProcessFields(new ExecutionPlan.ExecutionItem
+ {
+ Revision = new WiRevision
+ {
+ ParentOriginId = "2",
+ Fields = new List
+ {
+ new WiField { ReferenceName = WiFieldReference.Title, Value = "To Do" }
+ }
+ },
+ OriginId = "2",
+ IsFinal = true
+ });
+
+ // Act
+ var currentValue = _boardColumnCollector.GetCurrentValue("2");
+
+ // Assert
+ Assert.IsNull(currentValue);
+ }
+ }
+}
+
+
From 3326c1ed863dd53f1eda3ad59f5747ef5ad4e384 Mon Sep 17 00:00:00 2001
From: mammabear123 <127075115+mammabear123@users.noreply.github.com>
Date: Fri, 22 Dec 2023 17:33:37 +0800
Subject: [PATCH 3/4] Harden equals comparison against null RevisionReferences.
---
src/WorkItemMigrator/WorkItemImport/RevisionReference.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs b/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs
index ef2cfeb9..10c4f5ad 100644
--- a/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs
+++ b/src/WorkItemMigrator/WorkItemImport/RevisionReference.cs
@@ -23,7 +23,7 @@ public int CompareTo(RevisionReference other)
public bool Equals(RevisionReference other)
{
- return OriginId.Equals(other.OriginId, StringComparison.InvariantCultureIgnoreCase) && RevIndex == other.RevIndex;
+ return OriginId.Equals(other?.OriginId, StringComparison.InvariantCultureIgnoreCase) && RevIndex == other?.RevIndex;
}
public override bool Equals(object obj)
From 7b0e4dfcaac0ef3cd33c43389364b1c79589dcc1 Mon Sep 17 00:00:00 2001
From: mammabear123 <127075115+mammabear123@users.noreply.github.com>
Date: Thu, 25 Jan 2024 15:47:50 +0800
Subject: [PATCH 4/4] Remove unused isFinalRevision parameter.
---
src/WorkItemMigrator/WorkItemImport/Agent.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/WorkItemMigrator/WorkItemImport/Agent.cs b/src/WorkItemMigrator/WorkItemImport/Agent.cs
index ad70e36d..4bf74883 100644
--- a/src/WorkItemMigrator/WorkItemImport/Agent.cs
+++ b/src/WorkItemMigrator/WorkItemImport/Agent.cs
@@ -57,7 +57,7 @@ public WorkItem CreateWorkItem(string type, bool suppressNotifications, DateTime
return _witClientUtils.CreateWorkItem(type, suppressNotifications, createdDate, createdBy);
}
- public bool ImportRevision(WiRevision rev, WorkItem wi, Settings settings, bool isFinalRevision)
+ public bool ImportRevision(WiRevision rev, WorkItem wi, Settings settings)
{
var incomplete = false;
try