private WorkItem GetRightHandSideTargitWi(WorkItem wiSourceL, WorkItem wiSourceR, WorkItem wiTargetL, WorkItemStoreContext targetStore) { WorkItem wiTargetR; if (!(wiTargetL == null) && wiSourceR.Project.Name == wiTargetL.Project.Name && wiSourceR.Project.Store.TeamProjectCollection.Uri.ToString().Replace("/", "") == wiTargetL.Project.Store.TeamProjectCollection.Uri.ToString().Replace("/", "")) { // Moving to same team project as SourceR wiTargetR = wiSourceR; } else { // Moving to Other Team Project from Source wiTargetR = targetStore.FindReflectedWorkItem(wiSourceR, true); if (wiTargetR == null) // Assume source only (other team project) { wiTargetR = wiSourceR; if (wiTargetR.Project.Store.TeamProjectCollection.Uri.ToString().Replace("/", "") != wiSourceR.Project.Store.TeamProjectCollection.Uri.ToString().Replace("/", "")) { wiTargetR = null; // Totally bogus break! as not same team collection } } } return(wiTargetR); }
private void CreateRelatedLink(WorkItem wiSourceL, RelatedLink item, WorkItem wiTargetL, WorkItemStoreContext sourceStore, WorkItemStoreContext targetStore, bool save) { RelatedLink rl = (RelatedLink)item; WorkItem wiSourceR = null; WorkItem wiTargetR = null; try { wiSourceR = sourceStore.Store.GetWorkItem(rl.RelatedWorkItemId); } catch (Exception ex) { Trace.WriteLine(string.Format(" [FIND-FAIL] Adding Link of type {0} where wiSourceL={1}, wiTargetL={2} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiTargetL.Id)); Trace.TraceError(ex.ToString()); return; } try { wiTargetR = GetRightHandSideTargitWi(wiSourceL, wiSourceR, wiTargetL, targetStore); } catch (Exception ex) { Trace.WriteLine(string.Format(" [FIND-FAIL] Adding Link of type {0} where wiSourceL={1}, wiTargetL={2} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiTargetL.Id)); Trace.TraceError(ex.ToString()); return; } if (wiTargetR != null) { bool IsExisting = false; try { var exist = ( from Link l in wiTargetL.Links where l is RelatedLink && ((RelatedLink)l).RelatedWorkItemId == wiTargetR.Id && ((RelatedLink)l).LinkTypeEnd.ImmutableName == item.LinkTypeEnd.ImmutableName select(RelatedLink) l).SingleOrDefault(); IsExisting = (exist != null); } catch (Exception ex) { Trace.WriteLine(string.Format(" [SKIP] Unable to migrate links where wiSourceL={0}, wiSourceR={1}, wiTargetL={2}", ((wiSourceL != null) ? wiSourceL.Id.ToString() : "NotFound"), ((wiSourceR != null) ? wiSourceR.Id.ToString() : "NotFound"), ((wiTargetL != null) ? wiTargetL.Id.ToString() : "NotFound"))); Trace.TraceError(ex.ToString()); return; } if (!IsExisting && !wiTargetR.IsAccessDenied) { if (wiSourceR.Id != wiTargetR.Id) { Trace.WriteLine( string.Format(" [CREATE-START] Adding Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id)); WorkItemLinkTypeEnd linkTypeEnd = targetStore.Store.WorkItemLinkTypes.LinkTypeEnds[rl.LinkTypeEnd.ImmutableName]; RelatedLink newRl = new RelatedLink(linkTypeEnd, wiTargetR.Id); wiTargetL.Links.Add(newRl); if (save) { wiTargetL.Fields["System.ChangedBy"].Value = "Migration"; wiTargetL.Save(); } Trace.WriteLine( string.Format( " [CREATE-SUCCESS] Adding Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id)); } else { Trace.WriteLine( string.Format( " [SKIP] Unable to migrate link where Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} as target WI has not been migrated", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id)); } } else { if (IsExisting) { Trace.WriteLine(string.Format(" [SKIP] Already Exists a Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id)); } if (wiTargetR.IsAccessDenied) { Trace.WriteLine(string.Format(" [AccessDenied] The Target work item is inaccessable to create a Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id)); } } } else { Trace.WriteLine(string.Format(" [SKIP] Cant find wiTargetR where wiSourceL={0}, wiSourceR={1}, wiTargetL={2}", wiSourceL.Id, wiSourceR.Id, wiTargetL.Id)); } }
public void MigrateLinks(WorkItem sourceWorkItemLinkStart, WorkItemStoreContext sourceWorkItemStore, WorkItem targetWorkItemLinkStart, WorkItemStoreContext targetWorkItemStore, bool save = true) { if (targetWorkItemLinkStart.Links.Count == sourceWorkItemLinkStart.Links.Count) { Trace.WriteLine(string.Format("[SKIP] Source and Target have same number of links {0} - {1}", sourceWorkItemLinkStart.Id, sourceWorkItemLinkStart.Type.ToString()), "LinkMigrationContext"); } else { Trace.Indent(); foreach (Link item in sourceWorkItemLinkStart.Links) { try { Trace.WriteLine(string.Format("Migrating link for {0} of type {1}", sourceWorkItemLinkStart.Id, item.GetType().Name), "LinkMigrationContext"); if (IsHyperlink(item)) { CreateHyperlink((Hyperlink)item, targetWorkItemLinkStart, save); } else if (IsRelatedLink(item)) { RelatedLink rl = (RelatedLink)item; CreateRelatedLink(sourceWorkItemLinkStart, rl, targetWorkItemLinkStart, sourceWorkItemStore, targetWorkItemStore, save); } else if (IsExternalLink(item)) { var el = (ExternalLink)item; if (!IsBuildLink(el)) { CreateExternalLink(el, targetWorkItemLinkStart, save); } } else { UnknownLinkTypeException ex = new UnknownLinkTypeException(string.Format(" [UnknownLinkType] Unable to {0}", item.GetType().Name)); Telemetry.Current.TrackException(ex); Trace.WriteLine(ex.ToString(), "LinkMigrationContext"); throw ex; } } catch (WorkItemLinkValidationException ex) { sourceWorkItemLinkStart.Reset(); targetWorkItemLinkStart.Reset(); Telemetry.Current.TrackException(ex); Trace.WriteLine(string.Format(" [WorkItemLinkValidationException] Adding link for wiSourceL={0}", sourceWorkItemLinkStart.Id), "LinkMigrationContext"); Trace.WriteLine(ex.ToString(), "LinkMigrationContext"); } catch (FormatException ex) { sourceWorkItemLinkStart.Reset(); targetWorkItemLinkStart.Reset(); Telemetry.Current.TrackException(ex); Trace.WriteLine(string.Format(" [CREATE-FAIL] Adding Link for wiSourceL={0}", sourceWorkItemLinkStart.Id), "LinkMigrationContext"); Trace.WriteLine(ex.ToString(), "LinkMigrationContext"); } } } if (sourceWorkItemLinkStart.Type.Name == "Test Case") { MigrateSharedSteps(sourceWorkItemLinkStart, targetWorkItemLinkStart, sourceWorkItemStore, targetWorkItemStore, save); } }
private void CreateRelatedLink(WorkItem wiSourceL, RelatedLink item, WorkItem wiTargetL, WorkItemStoreContext sourceStore, WorkItemStoreContext targetStore, bool save, string sourceReflectedWIIdField) { RelatedLink rl = (RelatedLink)item; WorkItem wiSourceR = null; WorkItem wiTargetR = null; try { wiSourceR = sourceStore.Store.GetWorkItem(rl.RelatedWorkItemId); } catch (Exception ex) { Log.Error(ex, " [FIND-FAIL] Adding Link of type {0} where wiSourceL={1}, wiTargetL={2} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiTargetL.Id); return; } try { wiTargetR = GetRightHandSideTargetWi(wiSourceL, wiSourceR, wiTargetL, targetStore, sourceStore, sourceReflectedWIIdField); } catch (Exception ex) { Log.Error(ex, " [FIND-FAIL] Adding Link of type {0} where wiSourceL={1}, wiTargetL={2} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiTargetL.Id); return; } if (wiTargetR != null) { bool IsExisting = false; try { var exist = ( from Link l in wiTargetL.Links where l is RelatedLink && ((RelatedLink)l).RelatedWorkItemId == wiTargetR.Id && ((RelatedLink)l).LinkTypeEnd.ImmutableName == item.LinkTypeEnd.ImmutableName select(RelatedLink) l).SingleOrDefault(); IsExisting = (exist != null); } catch (Exception ex) { Log.Error(ex, " [SKIP] Unable to migrate links where wiSourceL={0}, wiSourceR={1}, wiTargetL={2}", ((wiSourceL != null) ? wiSourceL.Id.ToString() : "NotFound"), ((wiSourceR != null) ? wiSourceR.Id.ToString() : "NotFound"), ((wiTargetL != null) ? wiTargetL.Id.ToString() : "NotFound")); return; } if (!IsExisting && !wiTargetR.IsAccessDenied) { if (wiSourceR.Id != wiTargetR.Id) { Log.Information(" [CREATE-START] Adding Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id); WorkItemLinkTypeEnd linkTypeEnd = targetStore.Store.WorkItemLinkTypes.LinkTypeEnds[rl.LinkTypeEnd.ImmutableName]; RelatedLink newRl = new RelatedLink(linkTypeEnd, wiTargetR.Id); if (linkTypeEnd.ImmutableName == "System.LinkTypes.Hierarchy-Forward") { var potentialParentConflictLink = ( // TF201036: You cannot add a Child link between work items xxx and xxx because a work item can have only one Parent link. from Link l in wiTargetR.Links where l is RelatedLink && ((RelatedLink)l).LinkTypeEnd.ImmutableName == "System.LinkTypes.Hierarchy-Reverse" select(RelatedLink) l).SingleOrDefault(); if (potentialParentConflictLink != null) { wiTargetR.Links.Remove(potentialParentConflictLink); } linkTypeEnd = targetStore.Store.WorkItemLinkTypes.LinkTypeEnds["System.LinkTypes.Hierarchy-Reverse"]; RelatedLink newLl = new RelatedLink(linkTypeEnd, wiTargetL.Id); wiTargetR.Links.Add(newLl); wiTargetR.Fields["System.ChangedBy"].Value = "Migration"; wiTargetR.Save(); } else { if (linkTypeEnd.ImmutableName == "System.LinkTypes.Hierarchy-Reverse") { var potentialParentConflictLink = ( // TF201065: You can not add a Parent link to this work item because a work item can have only one link of this type. from Link l in wiTargetL.Links where l is RelatedLink && ((RelatedLink)l).LinkTypeEnd.ImmutableName == "System.LinkTypes.Hierarchy-Reverse" select(RelatedLink) l).SingleOrDefault(); if (potentialParentConflictLink != null) { wiTargetL.Links.Remove(potentialParentConflictLink); } } wiTargetL.Links.Add(newRl); if (save) { wiTargetL.Fields["System.ChangedBy"].Value = "Migration"; wiTargetL.Save(); } } Log.Information( " [CREATE-SUCCESS] Adding Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id); } else { Log.Information( " [SKIP] Unable to migrate link where Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} as target WI has not been migrated", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id); } } else { if (IsExisting) { Log.Information(" [SKIP] Already Exists a Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id); } if (wiTargetR.IsAccessDenied) { Log.Information(" [AccessDenied] The Target work item is inaccessable to create a Link of type {0} where wiSourceL={1}, wiSourceR={2}, wiTargetL={3}, wiTargetR={4} ", rl.LinkTypeEnd.ImmutableName, wiSourceL.Id, wiSourceR.Id, wiTargetL.Id, wiTargetR.Id); } } } else { Log.Information(" [SKIP] Cant find wiTargetR where wiSourceL={0}, wiSourceR={1}, wiTargetL={2}", wiSourceL.Id, wiSourceR.Id, wiTargetL.Id); } }
public void MigrateLinks(WorkItem sourceWorkItemLinkStart, WorkItemStoreContext sourceWorkItemStore, WorkItem targetWorkItemLinkStart, WorkItemStoreContext targetWorkItemStore, bool save = true, bool filterWorkItemsThatAlreadyExistInTarget = true, string sourceReflectedWIIdField = null) { if (ShouldCopyLinks(sourceWorkItemLinkStart, targetWorkItemLinkStart, filterWorkItemsThatAlreadyExistInTarget)) { Trace.Indent(); foreach (Link item in sourceWorkItemLinkStart.Links) { try { Log.Information("Migrating link for {sourceWorkItemLinkStartId} of type {ItemGetTypeName}", sourceWorkItemLinkStart.Id, item.GetType().Name); if (IsHyperlink(item)) { CreateHyperlink((Hyperlink)item, targetWorkItemLinkStart, save); } else if (IsRelatedLink(item)) { RelatedLink rl = (RelatedLink)item; CreateRelatedLink(sourceWorkItemLinkStart, rl, targetWorkItemLinkStart, sourceWorkItemStore, targetWorkItemStore, save, sourceReflectedWIIdField); } else if (IsExternalLink(item)) { var el = (ExternalLink)item; if (!IsBuildLink(el)) { CreateExternalLink(el, targetWorkItemLinkStart, save); } } else { UnknownLinkTypeException ex = new UnknownLinkTypeException(string.Format(" [UnknownLinkType] Unable to {0}", item.GetType().Name)); Log.Error(ex, "LinkMigrationContext"); throw ex; } } catch (WorkItemLinkValidationException ex) { sourceWorkItemLinkStart.Reset(); targetWorkItemLinkStart.Reset(); Log.Error(ex, "[WorkItemLinkValidationException] Adding link for wiSourceL={sourceWorkItemLinkStartId}", sourceWorkItemLinkStart.Id); } catch (FormatException ex) { sourceWorkItemLinkStart.Reset(); targetWorkItemLinkStart.Reset(); Log.Error(ex, "[CREATE-FAIL] Adding Link for wiSourceL={sourceWorkItemLinkStartId}", sourceWorkItemLinkStart.Id); } } } if (sourceWorkItemLinkStart.Type.Name == "Test Case") { MigrateSharedSteps(sourceWorkItemLinkStart, targetWorkItemLinkStart, sourceWorkItemStore, targetWorkItemStore, save); } }
public int FixExternalLinks(WorkItem targetWorkItem, WorkItemStoreContext targetStore, WorkItem sourceWorkItem, bool save = true) { List <ExternalLink> newEL = new List <ExternalLink>(); List <ExternalLink> removeEL = new List <ExternalLink>(); int count = 0; foreach (Link l in targetWorkItem.Links) { if (l is ExternalLink && gitWits.Contains(l.ArtifactLinkType.Name)) { ExternalLink el = (ExternalLink)l; GitRepositoryInfo sourceRepoInfo = GitRepositoryInfo.Create(el, sourceRepos, migrationEngine, sourceWorkItem?.Project?.Name); // if sourceRepo is null ignore this link and keep processing further links if (sourceRepoInfo == null) { continue; } // if repo was not found in source project, try to find it by repoId in the whole project collection if (sourceRepoInfo.GitRepo == null) { var anyProjectSourceRepoInfo = GitRepositoryInfo.Create(el, allSourceRepos, migrationEngine, sourceWorkItem?.Project?.Name); // if repo is found in a different project and the repo Name is listed in repo mappings, use it if (anyProjectSourceRepoInfo.GitRepo != null && migrationEngine.GitRepoMappings.ContainsKey(anyProjectSourceRepoInfo.GitRepo.Name)) { sourceRepoInfo = anyProjectSourceRepoInfo; } else { Trace.WriteLine($"FAIL could not find source git repo - repo referenced: {anyProjectSourceRepoInfo?.GitRepo?.ProjectReference?.Name}/{anyProjectSourceRepoInfo?.GitRepo?.Name}"); } } if (sourceRepoInfo.GitRepo != null) { string targetRepoName = GetTargetRepoName(migrationEngine.GitRepoMappings, sourceRepoInfo); string sourceProjectName = sourceRepoInfo?.GitRepo?.ProjectReference?.Name ?? migrationEngine.Target.Config.Project; string targetProjectName = migrationEngine.Target.Config.Project; GitRepositoryInfo targetRepoInfo = GitRepositoryInfo.Create(targetRepoName, sourceRepoInfo, targetRepos); // if repo was not found in the target project, try to find it in the whole target project collection if (targetRepoInfo.GitRepo == null) { if (migrationEngine.GitRepoMappings.ContainsValue(targetRepoName)) { var anyTargetRepoInCollectionInfo = GitRepositoryInfo.Create(targetRepoName, sourceRepoInfo, allTargetRepos); if (anyTargetRepoInCollectionInfo.GitRepo != null) { targetRepoInfo = anyTargetRepoInCollectionInfo; } } } // Fix commit links if target repo has been found if (targetRepoInfo.GitRepo != null) { Trace.WriteLine($"Fixing {sourceRepoInfo.GitRepo.RemoteUrl} to {targetRepoInfo.GitRepo.RemoteUrl}?"); // Create External Link object ExternalLink newLink = null; switch (l.ArtifactLinkType.Name) { case "Branch": newLink = new ExternalLink(targetStore.Store.RegisteredLinkTypes[ArtifactLinkIds.Branch], $"vstfs:///git/ref/{targetRepoInfo.GitRepo.ProjectReference.Id}%2f{targetRepoInfo.GitRepo.Id}%2f{sourceRepoInfo.CommitID}"); break; case "Fixed in Changeset": // TFVC case "Fixed in Commit": newLink = new ExternalLink(targetStore.Store.RegisteredLinkTypes[ArtifactLinkIds.Commit], $"vstfs:///git/commit/{targetRepoInfo.GitRepo.ProjectReference.Id}%2f{targetRepoInfo.GitRepo.Id}%2f{sourceRepoInfo.CommitID}"); break; case "Pull Request": //newLink = new ExternalLink(targetStore.Store.RegisteredLinkTypes[ArtifactLinkIds.PullRequest], // $"vstfs:///Git/PullRequestId/{targetRepoInfo.GitRepo.ProjectReference.Id}%2f{targetRepoInfo.GitRepo.Id}%2f{sourceRepoInfo.CommitID}"); removeEL.Add(el); break; default: Trace.WriteLine(String.Format("Skipping unsupported link type {0}", l.ArtifactLinkType.Name)); break; } if (newLink != null) { var elinks = from Link lq in targetWorkItem.Links where gitWits.Contains(lq.ArtifactLinkType.Name) select(ExternalLink) lq; var found = (from Link lq in elinks where (((ExternalLink)lq).LinkedArtifactUri.ToLower() == newLink.LinkedArtifactUri.ToLower()) select lq).SingleOrDefault(); if (found == null) { newEL.Add(newLink); } removeEL.Add(el); } } else { Trace.WriteLine($"FAIL: cannot map {sourceRepoInfo.GitRepo.RemoteUrl} to ???"); } } } } // add and remove foreach (ExternalLink eln in newEL) { try { Trace.WriteLine("Adding " + eln.LinkedArtifactUri); targetWorkItem.Links.Add(eln); } catch (Exception) { // eat exception as sometimes TFS thinks this is an attachment } } foreach (ExternalLink elr in removeEL) { if (targetWorkItem.Links.Contains(elr)) { try { Trace.WriteLine("Removing " + elr.LinkedArtifactUri); targetWorkItem.Links.Remove(elr); count++; } catch (Exception) { // eat exception as sometimes TFS thinks this is an attachment } } } if (targetWorkItem.IsDirty && save) { Trace.WriteLine($"Saving {targetWorkItem.Id}"); targetWorkItem.Fields["System.ChangedBy"].Value = "Migration"; targetWorkItem.Save(); } return(count); }