Well, it has been a long road from misery to hope with a little disbelief thrown in for good measure, but I finally have a working Adapter for the TFS Integration Platform.
Acknowledgements
- Jose Luis Soria Teruel – For his excellent advice and some sample code. I only used some of his code, but knowing that it can be done is the first step to achieving the goal.
Updates
- 2011-06-06 11:00 – I found a last minute bug where by the adapter thinks that a work item that was created before the high water mark but was not in scope before it was edited was converted to an “Edit” Change Action instead of a “Add”. I updated lines 89 and 102 of the source. The result is a WorkItemHistoryNotFound conflict
1234567891011121314[06/06/2011 10:12:14] MigrationConsole.exe Information: 0 : WorkItemTracking: Processing ChangeGroup #3214, change 3143:2[06/06/2011 10:12:15] MigrationConsole.exe Information: 0 : WorkItemTracking: Unresolved conflict:[06/06/2011 10:12:15] Session: adea805d-51df-489a-b2fd-9717b4af3703[06/06/2011 10:12:15] Source: 6e3bdf70-f1ae-4cd5-8ee4-133c8aee0857[06/06/2011 10:12:15] Message: Cannot find applicable resolution rule.[06/06/2011 10:12:15] Conflict Type: TFS WIT history not found conflict type[06/06/2011 10:12:15] Conflict Type Reference Name: 1722df87-ab61-4ad0-8b41-531d3d804089[06/06/2011 10:12:15] Conflict Details: <?xml version="1.0"?>[06/06/2011 10:12:15] <WorkItemHistoryNotFoundConflictTypeDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">[06/06/2011 10:12:15] <SourceWorkItemID>3143</SourceWorkItemID>[06/06/2011 10:12:15] <SourceWorkItemRevision>2</SourceWorkItemRevision>[06/06/2011 10:12:15] <SourceMigrationSourceId>c513f930-2602-400d-a0bf-a2a3ab434df5</SourceMigrationSourceId>[06/06/2011 10:12:15] <TargetMigrationSourceId>6e3bdf70-f1ae-4cd5-8ee4-133c8aee0857</TargetMigrationSourceId>[06/06/2011 10:12:15] </WorkItemHistoryNotFoundConflictTypeDetails>
With the new code, which has gone through many refactors for the sake of last ditch efforts to figure out the bug I am now able to update TFS from TTP in an incremental fashion.
Figure: Work Items are now being updated
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
; title="Full source for Analysis Provider"]Imports Microsoft.TeamFoundation.Migration.Toolkit Imports System.ComponentModel.Design Imports System.Collections.ObjectModel Imports Microsoft.TeamFoundation.Migration.Toolkit.Services Imports Microsoft.TeamFoundation.Migration.BusinessModel Imports Microsoft.TeamFoundation.Migration.Toolkit.ErrorManagement Imports System.Globalization Imports System.Xml Imports Microsoft.TeamFoundation.Migration.Toolkit.SyncOrchestrator Imports System.Net Imports System.IO Imports System.ServiceModel Imports System.ServiceModel.Security Imports NorthwestCadence.TtpTipAdapter.TtpSoapSdk Imports NorthwestCadence.TtpTipAdapter.TtpSoapSdk.api Public Class TtpAnalysisProvider Inherits AnalysisProviderBase ' Fields Private _analysisServiceContainer As IServiceContainer Private _changeGroupService As ChangeGroupService Private _configurationService As ConfigurationService Private _conflictManagerService As ConflictManager Private _highWaterMarkDelta As HighWaterMark(Of DateTime) Private _highWaterMarkChangeSet As HighWaterMark(Of Integer) Private _supportedChangeActions As Dictionary(Of Guid, ChangeActionHandler) Private _supportedContentTypes As Collection(Of ContentType) Private _dataSourceConfig As TtpMigrationDataSource Private _highWaterMarkRevisions As New Dictionary(Of String, HighWaterMark(Of Integer)) Private _tstart As DateTime = Now ' Properties Public Overrides ReadOnly Property SupportedChangeActions As Dictionary(Of Guid, ChangeActionHandler) Get Return Me._supportedChangeActions End Get End Property Public Overrides ReadOnly Property SupportedContentTypes As Collection(Of ContentType) Get Return Me._supportedContentTypes End Get End Property Private Shared Function CreateFieldRevisionDescriptionDoc(row As TtpDefectMigrationItem) As XmlDocument Dim columns As New XElement("Columns", New Object() {New XElement("Column", New Object() {New XAttribute("DisplayName", "Author"), New XAttribute("ReferenceName", "Author"), New XAttribute("Type", "String"), New XElement("Value", row.AuthorId)}), New XElement("Column", New Object() {New XAttribute("DisplayName", "DisplayName"), New XAttribute("ReferenceName", "DisplayName"), New XAttribute("Type", "String"), New XElement("Value", row.DisplayName)}), New XElement("Column", New Object() {New XAttribute("DisplayName", "Id"), New XAttribute("ReferenceName", "Id"), New XAttribute("Type", "String"), New XElement("Value", row.Id.ToString)})}) Dim column As KeyValuePair(Of String, Object) For Each column In row.Columns If Not String.IsNullOrEmpty(column.Value) Then columns.Add(New XElement("Column", New Object() {New XAttribute("DisplayName", column.Key), New XAttribute("ReferenceName", column.Key), New XAttribute("Type", "String"), New XElement("Value", column.Value)})) End If Next Dim descriptionDoc As New XElement("WorkItemChanges", New Object() {New XAttribute("Revision", row.Revision), New XAttribute("WorkItemType", row.WorItemType), New XAttribute("Author", IIf(String.IsNullOrEmpty(row.AuthorId), "", row.AuthorId)), New XAttribute("ChangeDate", row.ModifiedOn.ToString(CultureInfo.CurrentCulture)), New XAttribute("WorkItemID", row.Id.ToString), columns}) Dim doc As New XmlDocument doc.LoadXml(descriptionDoc.ToString) Return doc End Function Private Shared Function CreateFieldColumn(migrationActionDetails As XmlDocument, displayName As String, referenceName As String, fieldType As String, value As Object, isSkippingField As Boolean) As XmlElement Dim c As XmlElement = migrationActionDetails.CreateElement("Column") c.SetAttribute("DisplayName", displayName) c.SetAttribute("ReferenceName", referenceName) c.SetAttribute("Type", fieldType) c.SetAttribute("IsSkippingField", isSkippingField.ToString()) Dim v As XmlElement = migrationActionDetails.CreateElement("Value") 'object translatedValue = TranslateFieldValue(f, fieldValue); Dim translatedValue As Object = value If translatedValue Is Nothing Then v.InnerText = String.Empty Else translatedValue.ToString() End If c.AppendChild(v) Return c End Function Public Overrides Sub GenerateDeltaTable() _tstart = Now Try Dim viewName As String = Me._configurationService.Filters.Item(0).Path TraceManager.TraceInformation("TtpWIT:AP:GenerateDeltaTable:View - {0}", New Object() {viewName}) Me._highWaterMarkDelta.Reload() '------------------------------------------------------ Dim context As TtpContext = GetTtpContext() Dim raw As List(Of TtpDefectMigrationItem) = GetTtpRawData(context, viewName) TraceManager.TraceInformation("Located {0} raw updates since {1} in {2} seconds", raw.Count, _highWaterMarkDelta.Value, Now.Subtract(_tstart).TotalSeconds) ' Find all of the data that needs to be added in this run Dim deltaNew = (From ri In raw Where ri.CreatedOn.CompareTo(_highWaterMarkDelta.Value) > 0 Or ri.Revision = 0).ToList ' Get any extra data and create the add changesets TraceManager.TraceInformation("Located {0} deltas as NEW in {1} seconds", deltaNew.Count, Now.Subtract(_tstart).TotalSeconds) deltaNew = GetDeltaWorkflow(context, deltaNew) TraceManager.TraceInformation("Updated {0} deltas with workflow in {1} seconds", deltaNew.Count, Now.Subtract(_tstart).TotalSeconds) Dim changesNew As List(Of ChangeGroup) = GetChangeGroupsForAdds(deltaNew) TraceManager.TraceInformation("Created {0} add change groups in {1} seconds", changesNew.Count, Now.Subtract(_tstart).TotalSeconds) ' Save the chnagesets to the backing store For Each c In changesNew c.Save() Next TraceManager.TraceInformation("Saved {0} add change groups in {1} seconds", changesNew.Count, Now.Subtract(_tstart).TotalSeconds) ' Find all of the data that needs to be edited in this run Dim deltaEdit = (From ri In raw Where (ri.ModifiedOn.CompareTo(_highWaterMarkDelta.Value) > 0 And Not ri.CreatedOn.CompareTo(_highWaterMarkDelta.Value) > 0) Or ri.Revision > 0).ToList ' Get any extra data and create the edit changesets TraceManager.TraceInformation("Located {0} deltas as EDIT in {1} seconds", deltaEdit.Count, Now.Subtract(_tstart).TotalSeconds) deltaEdit = GetDeltaWorkflow(context, deltaEdit) TraceManager.TraceInformation("Updated {0} deltas with workflow in {1} seconds", deltaEdit.Count, Now.Subtract(_tstart).TotalSeconds) Dim changesEdit As List(Of ChangeGroup) = GetChangeGroupsForEdits(deltaEdit) TraceManager.TraceInformation("Created {0} edit change groups in {1} seconds", changesEdit.Count, Now.Subtract(_tstart).TotalSeconds) ' Save the chnagesets to the backing store For Each c In changesEdit c.Save() Next TraceManager.TraceInformation("Saved {0} edit change groups in {1} seconds", changesEdit.Count, Now.Subtract(_tstart).TotalSeconds) '------------------------------------------------------ ' Update the High water mark and send the changes through Me._highWaterMarkDelta.Update(DateTime.Now) Me._changeGroupService.PromoteDeltaToPending() Catch ex As Exception TraceManager.TraceException(ex) End Try End Sub Public Overrides Sub InitializeClient() TraceManager.TraceInformation("TtpWIT:AP:InitializeClient") End Sub Private Shared Function InitializeMigrationDataSource() As TtpMigrationDataSource Return New TtpMigrationDataSource End Function Public Overrides Sub InitializeServices(ByVal analysisService As IServiceContainer) TraceManager.TraceInformation("TtpWIT:AP:InitializeServices") If (analysisService Is Nothing) Then Throw New ArgumentNullException("analysisService") End If Me._analysisServiceContainer = analysisService Me._configurationService = DirectCast(analysisService.GetService(GetType(ConfigurationService)), ConfigurationService) Dim migrationSourceConfiguration As MigrationSource = Me._configurationService.MigrationSource _dataSourceConfig = TtpAnalysisProvider.InitializeMigrationDataSource Dim customSetting As CustomSetting Dim username As String = "" Dim password As String = "" Dim IsWorkflowIncluded As Boolean = True Dim hwmDateOveride As DateTime = DateTime.MinValue For Each customSetting In Me._configurationService.MigrationSource.CustomSettings.CustomSetting If customSetting.SettingKey.Equals("Username", StringComparison.OrdinalIgnoreCase) Then username = customSetting.SettingValue End If If customSetting.SettingKey.Equals("Password", StringComparison.OrdinalIgnoreCase) Then password = customSetting.SettingValue End If If customSetting.SettingKey.Equals("OverrideHWM", StringComparison.OrdinalIgnoreCase) Then If Not DateTime.TryParse(customSetting.SettingValue, hwmDateOveride) Then Throw New InvalidCastException("Date is not in the correct format: OverrideHWM") End If End If If customSetting.SettingKey.Equals("IsWorkflowIncluded", StringComparison.OrdinalIgnoreCase) Then If Not Boolean.TryParse(customSetting.SettingValue, IsWorkflowIncluded) Then Throw New InvalidCastException("Date is not in the correct format: IsWorkflowIncluded") End If End If Next _dataSourceConfig.Credentials = New NetworkCredential(username, password) _dataSourceConfig.DatabaseName = migrationSourceConfiguration.SourceIdentifier _dataSourceConfig.FilterName = IIf(migrationSourceConfiguration.ServerIdentifier = "[enterFiltername]", "", migrationSourceConfiguration.ServerIdentifier) _dataSourceConfig.Url = migrationSourceConfiguration.ServerUrl _dataSourceConfig.IsWorkflowIncluded = IsWorkflowIncluded Me._supportedContentTypes = New Collection(Of ContentType) Me.SupportedContentTypes.Add(WellKnownContentType.WorkItem) Dim handler As New TtpChangeActionHandlers(Me) Me._supportedChangeActions = New Dictionary(Of Guid, ChangeActionHandler) Me.SupportedChangeActions.Add(WellKnownChangeActionId.Add, New ChangeActionHandler(AddressOf handler.BasicActionHandler)) Me.SupportedChangeActions.Add(WellKnownChangeActionId.Edit, New ChangeActionHandler(AddressOf handler.BasicActionHandler)) Me.SupportedChangeActions.Add(WellKnownChangeActionId.Delete, New ChangeActionHandler(AddressOf handler.BasicActionHandler)) Me._highWaterMarkDelta = New HighWaterMark(Of DateTime)("HWMDelta") Me._highWaterMarkChangeSet = New HighWaterMark(Of Integer)("LastChangeSet") Me._configurationService.RegisterHighWaterMarkWithSession(Me._highWaterMarkDelta) Me._configurationService.RegisterHighWaterMarkWithSession(Me._highWaterMarkChangeSet) If hwmDateOveride > DateTime.MinValue Then _highWaterMarkDelta.Update(hwmDateOveride) End If Me._changeGroupService = DirectCast(Me._analysisServiceContainer.GetService(GetType(ChangeGroupService)), ChangeGroupService) Me._changeGroupService.RegisterDefaultSourceSerializer(New TtpDefectMigrationItemSerializer) End Sub Public Overrides Sub RegisterConflictTypes(ByVal conflictManager As ConflictManager) TraceManager.TraceInformation("TtpWIT:AP:RegisterConflictTypes") Me._conflictManagerService = DirectCast(Me._analysisServiceContainer.GetService(GetType(ConflictManager)), ConflictManager) Me._conflictManagerService.RegisterConflictType(New GenericConflictType) Me._conflictManagerService.RegisterConflictType(New TtpGeneralConflictType, ConflictsSyncOrchOptions.Continue) End Sub Public Overrides Sub RegisterSupportedChangeActions(ByVal changeActionRegistrationService As ChangeActionRegistrationService) TraceManager.TraceInformation("TtpWIT:AP:RegisterSupportedChangeActions") changeActionRegistrationService = DirectCast(Me._analysisServiceContainer.GetService(GetType(ChangeActionRegistrationService)), ChangeActionRegistrationService) Dim supportedChangeAction As KeyValuePair(Of Guid, ChangeActionHandler) For Each supportedChangeAction In Me.SupportedChangeActions Dim contentType As ContentType For Each contentType In Me.SupportedContentTypes changeActionRegistrationService.RegisterChangeAction(supportedChangeAction.Key, contentType.ReferenceName, supportedChangeAction.Value) Next Next End Sub Public Overrides Sub RegisterSupportedContentTypes(contentTypeRegistrationService As Microsoft.TeamFoundation.Migration.Toolkit.Services.ContentTypeRegistrationService) End Sub Private Function GetTtpContext() As TtpContext TraceManager.TraceInformation("-GetTtpContext") Dim TtpServer As Uri = New Uri(String.Format("{0}/scripts/ttsoapcgi.exe", _dataSourceConfig.Url)) TraceManager.TraceInformation(ChrW(9) & "-GetTtpContext Loading Ttp {0}", New Object() {TtpServer}) Dim context As TtpContext = Nothing Try context = TtpSoapSdkApi.CreateContext(TtpServer, _dataSourceConfig.DatabaseName, _dataSourceConfig.Credentials.UserName, _dataSourceConfig.Credentials.Password) TraceManager.TraceInformation("-GetTtpContext Connected to '{0}' on '{1}' in {2}", context.Project.database, TtpServer, Now.Subtract(_tstart).ToFriendly) Catch ex As Exception TraceManager.TraceException(ex) End Try Return context End Function Private Function GetTtpRawData(context As TtpContext, filter As String) As List(Of TtpDefectMigrationItem) Dim raw As New List(Of TtpDefectMigrationItem) Try Dim columns As List(Of CTableColumn) = context.GetColumns("Defect") TraceManager.TraceInformation("-GetTtpRawData '{0}' columns in {1}", columns.Count, Now.Subtract(_tstart).ToFriendly) TraceManager.TraceInformation("-GetTtpRawData Atempting get on all data") Dim rows As CRecordListSoap = context.GetRecords("Defect", filter, columns) TraceManager.TraceInformation("-GetTtpRawData Found {0} records in {1} seconds", rows.records.Count, Now.Subtract(_tstart).TotalSeconds) Dim currentRecord As Integer = 1 Dim countRecords = rows.records.Count For Each record In rows.records ' item has been modified since HWM & before deltra table start time Try Dim DefectMI As TtpDefectMigrationItem = TtpDefectMigrationItem.ConvertCDefectToTtpDefectMigrationItem(_configurationService, columns.ToArray, record) '---------------- raw.Add(DefectMI) TraceManager.TraceInformation("-GetTtpRawData {0} of {1} - '{2}' Number '{3}' has loaded in {4} seconds", currentRecord, countRecords, DefectMI.WorItemType, DefectMI.Id, Now.Subtract(_tstart).TotalSeconds) Catch ex As Exception TraceManager.TraceError("-GetTtpRawData {0} of {1} - '{2}' Number '{3}' has {4} processing in {5} seconds", currentRecord, countRecords, "unknown", "unknown", "failed", Now.Subtract(_tstart).TotalSeconds) TraceManager.TraceException(ex) End Try currentRecord = currentRecord + 1 Next Catch ex As Exception TraceManager.TraceException(ex) End Try Return raw End Function Private Function GetDeltaWorkflow(context As TtpContext, ByVal deltas As List(Of TtpDefectMigrationItem)) As List(Of TtpDefectMigrationItem) Try Dim currentRecord As Integer = 1 Dim countRecords = deltas.Count For Each di In deltas ' item has been modified since HWM & before deltra table start time If _dataSourceConfig.IsWorkflowIncluded Then di.ImportDefectData(context) TraceManager.TraceInformation("-GetDeltaWorkflow {0} of {1} - '{2}' Number '{3}' has {4} processing revision {5} in {6} seconds", currentRecord, countRecords, di.WorItemType, di.Id, "UPDATED", di.Revision, Now.Subtract(_tstart).TotalSeconds) Else TraceManager.TraceInformation("-GetDeltaWorkflow {0} of {1} - '{2}' Number '{3}' has {4} processing revision {5} in {6} seconds", currentRecord, countRecords, di.WorItemType, di.Id, "SKIPPED", di.Revision, Now.Subtract(_tstart).TotalSeconds) End If currentRecord = currentRecord + 1 Next Catch ex As Exception TraceManager.TraceException(ex) End Try Return deltas End Function Private Function GetChangeGroupsForAdds(ByVal deltas As List(Of TtpDefectMigrationItem)) As List(Of ChangeGroup) Dim changes As New List(Of ChangeGroup) Try Dim currentRecord As Integer = 1 Dim countRecords = deltas.Count For Each delta In deltas ' item has been modified since HWM & before deltra table start time Try ' Create and add acction group delta.ResetRevision() Dim changeGroup As ChangeGroup = Me._changeGroupService.CreateChangeGroupForDeltaTable(String.Format("{0}:{1}", delta.Id, delta.Revision)) changeGroup.Status = ChangeStatus.Delta changeGroup.Owner = Nothing changeGroup.Comment = String.Format(CultureInfo.CurrentCulture, "Changeset {0}", _highWaterMarkChangeSet.Value) changeGroup.ChangeTimeUtc = DateTime.UtcNow changeGroup.Status = ChangeStatus.Delta changeGroup.ExecutionOrder = 0 changeGroup.CreateAction( _ WellKnownChangeActionId.Add, _ delta, _ delta.Id, _ _dataSourceConfig.DatabaseName, _ delta.Revision, _ " ", _ WellKnownContentType.WorkItem.ReferenceName, _ TtpAnalysisProvider.CreateFieldRevisionDescriptionDoc(delta) _ ) changes.Add(changeGroup) _highWaterMarkChangeSet.Update((_highWaterMarkChangeSet.Value + 1)) ' DONE Catch ex As Exception TraceManager.TraceError("-GetChangeGroups {0} of {1} - '{2}' Number '{3}' has {4} processing in {5} seconds", currentRecord, countRecords, "unknown", "unknown", "failed", Now.Subtract(_tstart).TotalSeconds) TraceManager.TraceException(ex) End Try currentRecord = currentRecord + 1 Next Catch ex As Exception TraceManager.TraceException(ex) End Try Return changes End Function Private Function GetChangeGroupsForEdits(ByVal deltas As List(Of TtpDefectMigrationItem)) As List(Of ChangeGroup) Dim changes As New List(Of ChangeGroup) Try Dim currentRecord As Integer = 1 Dim countRecords = deltas.Count For Each delta In deltas ' item has been modified since HWM & before deltra table start time Try ' Create and add acction group delta.IncrementRevision() Dim changeGroup As ChangeGroup = Me._changeGroupService.CreateChangeGroupForDeltaTable(String.Format("{0}:{1}", delta.Id, delta.Revision)) changeGroup.Status = ChangeStatus.Delta changeGroup.Owner = Nothing changeGroup.Comment = String.Format(CultureInfo.CurrentCulture, "Changeset {0}", _highWaterMarkChangeSet.Value) changeGroup.ChangeTimeUtc = DateTime.UtcNow changeGroup.Status = ChangeStatus.Delta changeGroup.ExecutionOrder = 0 changeGroup.CreateAction( _ WellKnownChangeActionId.Edit, _ delta, _ delta.Id, _ _dataSourceConfig.DatabaseName, _ delta.Revision, _ " ", _ WellKnownContentType.WorkItem.ReferenceName, _ TtpAnalysisProvider.CreateFieldRevisionDescriptionDoc(delta) _ ) changes.Add(changeGroup) _highWaterMarkChangeSet.Update((_highWaterMarkChangeSet.Value + 1)) ' DONE Catch ex As Exception TraceManager.TraceError("-GetChangeGroups {0} of {1} - '{2}' Number '{3}' has {4} processing in {5} seconds", currentRecord, countRecords, "unknown", "unknown", "failed", Now.Subtract(_tstart).TotalSeconds) TraceManager.TraceException(ex) End Try currentRecord = currentRecord + 1 Next Catch ex As Exception TraceManager.TraceException(ex) End Try Return changes End Function End Class |
Figure: Full source for the Analysis Provider
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
Private Function GetChangeGroupsForEdits(ByVal deltas As List(Of TtpDefectMigrationItem)) As List(Of ChangeGroup) Dim changes As New List(Of ChangeGroup) Try Dim currentRecord As Integer = 1 Dim countRecords = deltas.Count For Each delta In deltas ' item has been modified since HWM & before deltra table start time Try ' Create and add acction group delta.IncrementRevision() Dim changeGroup As ChangeGroup = Me._changeGroupService.CreateChangeGroupForDeltaTable(String.Format("{0}:{1}", delta.Id, delta.Revision)) changeGroup.Status = ChangeStatus.Delta changeGroup.Owner = Nothing changeGroup.Comment = String.Format(CultureInfo.CurrentCulture, "Changeset {0}", _highWaterMarkChangeSet.Value) changeGroup.ChangeTimeUtc = DateTime.UtcNow changeGroup.Status = ChangeStatus.Delta changeGroup.ExecutionOrder = 0 changeGroup.CreateAction( _ WellKnownChangeActionId.Edit, _ delta, _ delta.Id, _ _dataSourceConfig.DatabaseName, _ delta.Revision, _ " ", _ WellKnownContentType.WorkItem.ReferenceName, _ TtpAnalysisProvider.CreateFieldRevisionDescriptionDoc(delta) _ ) changes.Add(changeGroup) _highWaterMarkChangeSet.Update((_highWaterMarkChangeSet.Value + 1)) ' DONE Catch ex As Exception TraceManager.TraceError("-GetChangeGroups {0} of {1} - '{2}' Number '{3}' has {4} processing in {5} seconds", currentRecord, countRecords, "unknown", "unknown", "failed", Now.Subtract(_tstart).TotalSeconds) TraceManager.TraceException(ex) End Try currentRecord = currentRecord + 1 Next Catch ex As Exception TraceManager.TraceException(ex) End Try Return changes End Function |
Figure: New code to get change groups
I am not exactly positive what made the difference as much of my debugging efforts were hampered by the nasty query bug in TTP, but I am very glad that it is working. It looks like I do not need to have consecutive Revision’s although as I have already implemented the code for it I am not going to change it at this stage in the game.
It is now a mater of configuration, but I am creating a table with all of the values of the 120+ fields as well as a neat table for the workflow and inserting it into the history.
Figure: Loooong history built from TTP Data
This history shows all of the values for the fields at the point in time that the data was migrated.
All in, I am quite happy with the process and will be implementing in production really soon. Still some testing to do, but all looks good so far.
- Can you share your experiences of creating a TFS Integration Platform Adapter?
-Every company deserves working software that successfully and consistently meets your customers needs. We can help you get working software with continuous feedback so that you agile teams can deliver continuous value with Visual Studio, Team Foundation Server & Scrum. We have experts on hand to help improve your process and deliver more value at higher quality.
[subscribe] While we love helping you individually we provide much of our resultant consulting understanding here for you to use. By writing about our experiences we gain a better understanding of them ourselves. You can get notified of all content that we publish with our weekly newsletter and see exactly what we are doing and how we are doing it. [/subscribe]


















Pingback: TOC: TFS Integration Tools Blog Posts and Reference Sites - Willy's Cave - Site Home - MSDN Blogs
Pingback: What do you do with a Work Item History Not Found Conflict Type Details | Visual Studio ALM
Pingback: Configuring a PowerShell Adapter for the TFS Integration Platform | Visual Studio ALM
Pingback: Migrating ClearQuest 2003.06.xx to TFS 2010 with the TFS Integration Platform and a hammer (part 1) | Where Technology Meets Teamwork
Pingback: Migrating ClearQuest 2003.06.xx to TFS 2010 with the TFS Integration Platform and a hammer (part 1) - Where Technology Meets Teamwork
Pingback: TOC: TFS Integration Tools Blog Posts and Reference Sites - Willy's Reflections - Site Home - MSDN Blogs