Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 58 additions & 56 deletions Common/Migration/Phase2/Processors/GitCommitLinksProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using Logging;
using Common.Config;
using Microsoft.TeamFoundation.SourceControl.WebApi;
using System.Web;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.VisualStudio.Services.WebApi.Patch;

namespace Common.Migration
{
Expand All @@ -21,10 +25,22 @@ public bool IsEnabled(ConfigJson config)
{
return config.MoveGitLinks;
}
private Dictionary<string, string> sourceProjectReposDictionary = new Dictionary<string, string>();
private Dictionary<string, GitRepository> targetProjectReposDictionary = new Dictionary<string, GitRepository>();

public async Task Preprocess(IMigrationContext migrationContext, IBatchMigrationContext batchContext, IList<WorkItem> sourceWorkItems, IList<WorkItem> targetWorkItems)
{

//Build source repos dictionary
var sourceGitClient = migrationContext.SourceClient.Connection.GetClient<GitHttpClient>();
var sourceProjectRepositories = sourceGitClient.GetRepositoriesAsync(migrationContext.Config.SourceConnection.Project).Result;
sourceProjectReposDictionary = sourceProjectRepositories.ToDictionary(
r => r.Id.ToString(), r => r.Name);

//Build target repos dictionary
var targetGitClient = migrationContext.TargetClient.Connection.GetClient<GitHttpClient>();
var targetProjectRepositories = targetGitClient.GetRepositoriesAsync(migrationContext.Config.TargetConnection.Project).Result;
targetProjectReposDictionary = targetProjectRepositories.ToDictionary(
r => r.Name, r => r);
}

public async Task<IEnumerable<JsonPatchOperation>> Process(IMigrationContext migrationContext, IBatchMigrationContext batchContext, WorkItem sourceWorkItem, WorkItem targetWorkItem)
Expand All @@ -36,71 +52,56 @@ public async Task<IEnumerable<JsonPatchOperation>> Process(IMigrationContext mig
{
foreach (WorkItemRelation sourceGitCommitLinkRelation in sourceGitCommitLinksRelations)
{
string adjustedUrl = ConvertGitCommitLinkToHyperLink(sourceWorkItem.Id.Value, sourceGitCommitLinkRelation.Url, migrationContext.Config.SourceConnection.Account);
WorkItemRelation targetGitCommitHyperlinkRelation = GetGitCommitHyperlinkIfExistsOnTarget(targetWorkItem, adjustedUrl);

if (targetGitCommitHyperlinkRelation != null) // is on target
if (!sourceGitCommitLinkRelation.Url.Contains("Git/Commit"))
{
JsonPatchOperation gitCommitHyperlinkAddOperation = MigrationHelpers.GetRelationAddOperation(targetGitCommitHyperlinkRelation);
jsonPatchOperations.Add(gitCommitHyperlinkAddOperation);
continue;
}
else // is not on target
{
string comment = string.Empty;
if (sourceGitCommitLinkRelation.Attributes.ContainsKey(Constants.RelationAttributeComment))
{
comment = $"{sourceGitCommitLinkRelation.Attributes[Constants.RelationAttributeComment]}";
}

string adjustedComment = $"{Constants.RelationAttributeGitCommitCommentValue}{comment}";

WorkItemRelation newGitCommitLinkRelation = new WorkItemRelation();
newGitCommitLinkRelation.Rel = Constants.Hyperlink;
newGitCommitLinkRelation.Url = adjustedUrl;
newGitCommitLinkRelation.Attributes = new Dictionary<string, object>();
newGitCommitLinkRelation.Attributes[Constants.RelationAttributeComment] = adjustedComment;

JsonPatchOperation gitCommitHyperlinkAddOperation = MigrationHelpers.GetRelationAddOperation(newGitCommitLinkRelation);
jsonPatchOperations.Add(gitCommitHyperlinkAddOperation);
}
//ArtifactLink format:
//vstfs:///Git/Commit/{sourceProjGuid}%2f{sourceRepoGuid}%2f47cb466c1d1f8dd8e1b43b40ed8c3a3fec67e20d
var gitGuidsOnly = HttpUtility.UrlDecode(sourceGitCommitLinkRelation.Url)
.Replace("vstfs:///Git/Commit/", string.Empty);

//Take the source GUIDs of Project and Repo
var sourceGitLinkProjectGuid = gitGuidsOnly.Split('/')[0];
var sourceGitLinkRepoGuid = gitGuidsOnly.Split('/')[1];

//Convert to Repo name from GUID
var sourceGitLinkRepoName = sourceProjectReposDictionary[sourceGitLinkRepoGuid];

//Find the target GUIDs of Project and Repo
var targetGitLinkRepoGuid = targetProjectReposDictionary[sourceGitLinkRepoName].Id.ToString();
var targetGitLinkProjectGuid = targetProjectReposDictionary[sourceGitLinkRepoName].ProjectReference.Id.ToString();


var newLinks = new Dictionary<string, object>
{
{
"relations/-",
new
{
rel = "ArtifactLink",
url = sourceGitCommitLinkRelation.Url
.Replace(sourceGitLinkProjectGuid, targetGitLinkProjectGuid)
.Replace(sourceGitLinkRepoGuid, targetGitLinkRepoGuid),
attributes = new
{
name = "Fixed in Commit",
comment = "Added by the migration"
}
}
}
};

var gitCommitHyperlinkAddOperation = VssJsonPatchDocumentFactory.ConstructJsonPatchDocument(Operation.Add, newLinks);
jsonPatchOperations.Add(gitCommitHyperlinkAddOperation[0]);
}
}

return jsonPatchOperations;
}

private WorkItemRelation GetGitCommitHyperlinkIfExistsOnTarget(WorkItem targetWorkItem, string href)
{
if (targetWorkItem.Relations == null)
{
return null;
}

foreach (WorkItemRelation targetRelation in targetWorkItem.Relations)
{
if (targetRelation.Rel.Equals(Constants.Hyperlink) && targetRelation.Url.Equals(href, StringComparison.OrdinalIgnoreCase))
{
return targetRelation;
}
}

return null;
}

private object GetIdFromAttributes(WorkItemRelation relation)
{
if (relation.Attributes != null && relation.Attributes.ContainsKeyIgnoringCase(Constants.RelationAttributeId))
{
// get the key even if its letter case is different but it matches otherwise
string idKeyFromFields = relation.Attributes.GetKeyIgnoringCase(Constants.RelationAttributeId);
return relation.Attributes[idKeyFromFields];
}
else
{
return null;
}
}

private static IEnumerable<WorkItemRelation> GetGitLinksRelationsFromWorkItem(WorkItem workItem, string linkType, string account)
{
IList<WorkItemRelation> result = new List<WorkItemRelation>();
Expand All @@ -122,6 +123,7 @@ private static IEnumerable<WorkItemRelation> GetGitLinksRelationsFromWorkItem(Wo
return result;
}


/// <summary>
/// Convert the vstfs git commit link to a hyperlink which works
/// </summary>
Expand Down