public GitArtifactLinkDetails(WorkItemRelation artifactLink, int linkIndex) { Url = artifactLink.Url; Index = linkIndex; if (Url.Contains("Git")) { string[] ids = WebUtility.UrlDecode(Url).Split('/'); if (ids[4] == "Commit") { IsGitLink = true; CommitID = ids[7]; RepositoryID = Guid.Parse(ids[6]); ProjectId = Guid.Parse(ids[5]); LinkType = GitLinkType.Commit; } else if (ids[4] == "PullRequestId") { IsGitLink = true; ProjectId = Guid.Parse(ids[5]); LinkType = GitLinkType.PullRequest; RepositoryID = Guid.Parse(ids[6]); PullRequestID = int.Parse(ids[7]); } //we don't handle the other cases as for now like 'Ref'links to branches //else //{ // throw new ArgumentException("Link Type not recognized!"); //} } }
public static bool IsRelationHyperlinkToSourceWorkItem(IContext context, WorkItemRelation relation, int sourceId) { // only hyperlinks can contain the link to the source work item if (relation.Rel.Equals(Constants.Hyperlink, StringComparison.OrdinalIgnoreCase)) { var hyperlinkToSourceWorkItem = context.WorkItemIdsUris[sourceId]; var sourceParts = Regex.Split(hyperlinkToSourceWorkItem, "/_apis/wit/workitems/", RegexOptions.IgnoreCase); var targetParts = Regex.Split(relation.Url, "/_apis/wit/workitems/", RegexOptions.IgnoreCase); if (sourceParts.Length == 2 && targetParts.Length == 2) { var sourceIdPart = sourceParts.Last(); var targetIdPart = targetParts.Last(); var sourceAccountPart = sourceParts.First().Split("/", StringSplitOptions.RemoveEmptyEntries); var targetAccountPart = targetParts.First().Split("/", StringSplitOptions.RemoveEmptyEntries); // url of the work item can contain project which we want to ignore since the url we generate does not include project // and we just need to verify the ids are the same and the account are the same. if (sourceAccountPart.Length > 1 && targetAccountPart.Length > 1 && string.Equals(sourceIdPart, targetIdPart, StringComparison.OrdinalIgnoreCase) && string.Equals(sourceAccountPart[1], targetAccountPart[1], StringComparison.OrdinalIgnoreCase)) { return(true); } } } return(false); }
public static JsonPatchOperation AddLink(this JsonPatchDocument source, string linkType, string targetUrl) { var relation = new WorkItemRelation() { Rel = linkType, Url = targetUrl }; return(AddLink(source, relation)); }
internal WorkItemRelationWrapper(WorkItemWrapper item, string type, string url, string comment) { _item = item; _relation = new WorkItemRelation() { Rel = type, Url = url, Attributes = { { "comment", comment } } }; }
public static JsonPatchOperation GetRelationAddOperation(WorkItemRelation relation) { JsonPatchOperation jsonPatchOperation = new JsonPatchOperation(); jsonPatchOperation.Operation = Operation.Add; jsonPatchOperation.Path = $"/{Constants.Relations}/-"; jsonPatchOperation.Value = relation; return(jsonPatchOperation); }
public static int GetItemId(this WorkItemRelation o) { int id = 0; if (!string.IsNullOrWhiteSpace(o.Url)) { int.TryParse(o.Url.Split('/').Last(), out id); } return(id); }
internal static WorkItemRelationWrapper GetInstance() { WorkItemRelation real = default(WorkItemRelation); RealInstanceFactory(ref real); WorkItemRelationWrapper instance = WorkItemRelationWrapper.GetWrapper(real); InstanceFactory(ref instance); return(instance); }
public static JsonPatchOperation AddLink(this JsonPatchDocument source, WorkItemRelation relation) { var op = new JsonPatchOperation() { Operation = Operation.Add, Path = "/relations/-", Value = relation }; source.Add(op); return(op); }
internal WorkItemRelationWrapper(string type, string url, string comment) : this(url) { _relation = new WorkItemRelation() { Rel = type, Url = url, Attributes = new Dictionary <string, object> { { "comment", comment } } }; }
private bool IsRelationWorkItemLink(IMigrationContext migrationContext, WorkItemRelation relation) { if (migrationContext.ValidatedWorkItemLinkRelationTypes.Contains(relation.Rel)) { return(true); } else { return(false); } }
public static string GetCommentFromAttributes(WorkItemRelation relation) { if (relation.Attributes != null && relation.Attributes.ContainsKeyIgnoringCase(Constants.RelationAttributeComment)) { // get the key even if its letter case is different but it matches otherwise string commentKeyFromFields = relation.Attributes.GetKeyIgnoringCase(Constants.RelationAttributeComment); return(relation.Attributes[Constants.RelationAttributeComment].ToString()); } else { return(string.Empty); } }
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); } }
public async Task <IEnumerable <JsonPatchOperation> > Process(IMigrationContext migrationContext, IBatchMigrationContext batchContext, WorkItem sourceWorkItem, WorkItem targetWorkItem) { IList <JsonPatchOperation> jsonPatchOperations = new List <JsonPatchOperation>(); if (sourceWorkItem.Relations == null) { return(jsonPatchOperations); } IEnumerable <WorkItemRelation> sourceAttachmentWorkItemRelations = GetAttachmentWorkItemRelations(sourceWorkItem.Relations); if (sourceAttachmentWorkItemRelations.Any()) { foreach (WorkItemRelation sourceAttachmentWorkItemRelation in sourceAttachmentWorkItemRelations) { WorkItemRelation targetAttachmentRelation = GetAttachmentIfExistsOnTarget(targetWorkItem, sourceAttachmentWorkItemRelation); if (targetAttachmentRelation != null) // is on target { JsonPatchOperation attachmentAddOperation = MigrationHelpers.GetRelationAddOperation(targetAttachmentRelation); jsonPatchOperations.Add(attachmentAddOperation); } else // is not on target { AttachmentLink attachmentLink = await UploadAttachmentFromSourceRelation(migrationContext, batchContext, sourceWorkItem, sourceAttachmentWorkItemRelation, migrationContext.Config.MaxAttachmentSize); if (attachmentLink != null) { WorkItemRelation newAttachmentWorkItemRelation = new WorkItemRelation(); newAttachmentWorkItemRelation.Rel = sourceAttachmentWorkItemRelation.Rel; newAttachmentWorkItemRelation.Url = attachmentLink.AttachmentReference.Url; newAttachmentWorkItemRelation.Attributes = new Dictionary <string, object>(); newAttachmentWorkItemRelation.Attributes[Constants.RelationAttributeName] = attachmentLink.FileName; newAttachmentWorkItemRelation.Attributes[Constants.RelationAttributeResourceSize] = attachmentLink.ResourceSize; newAttachmentWorkItemRelation.Attributes[Constants.RelationAttributeComment] = attachmentLink.Comment; JsonPatchOperation attachmentAddOperation = MigrationHelpers.GetRelationAddOperation(newAttachmentWorkItemRelation); jsonPatchOperations.Add(attachmentAddOperation); } } } } return(jsonPatchOperations); }
/// <summary> /// Deeps the copy. /// </summary> /// <param name="wir">The Work Item Relationship</param> /// <returns>A clone of the input work item relationship</returns> private static WorkItemRelation DeepCopy(this WorkItemRelation wir) { var newWorkItemRelation = new WorkItemRelation { Attributes = new Dictionary <string, object>(), Rel = wir.Rel, Title = wir.Title, Url = wir.Url }; if (wir.Attributes != null && wir.Attributes?.Count > 0) { foreach (var item in wir.Attributes) { newWorkItemRelation.Attributes.Add(item.Key, item.Value); } } return(newWorkItemRelation); }
public async Task <IEnumerable <JsonPatchOperation> > Process(IMigrationContext migrationContext, IBatchMigrationContext batchContext, WorkItem sourceWorkItem, WorkItem targetWorkItem) { IList <JsonPatchOperation> jsonPatchOperations = new List <JsonPatchOperation>(); IEnumerable <WorkItemRelation> sourceGitCommitLinksRelations = GetGitLinksRelationsFromWorkItem(sourceWorkItem, Constants.RelationArtifactLink, migrationContext.Config.SourceConnection.Account); if (sourceGitCommitLinksRelations.Any()) { 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 { JsonPatchOperation gitCommitHyperlinkAddOperation = MigrationHelpers.GetRelationAddOperation(targetGitCommitHyperlinkRelation); jsonPatchOperations.Add(gitCommitHyperlinkAddOperation); } 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); } } } return(jsonPatchOperations); }
/// <summary>Gets the Guid of the related item.</summary> /// <param name="source">The source.</param> /// <returns>The Guid of the related item or 0 if it cannot be found.</returns> /// <remarks> /// The related Guid isn't available directly but has to be determined by parsing the URL. Only work items are supported right now. /// </remarks> public static Guid GetRelatedGuid(this WorkItemRelation source) { //Parse the URL, the Guid is the last value var url = source.Url; if (!String.IsNullOrEmpty(url)) { //Skip to the last value var idStringIndex = url.LastIndexOf('/'); if (idStringIndex >= 0) { var idString = url.Substring(idStringIndex + 1); if (Guid.TryParse(idString, out var guid)) { return(guid); } } } return(Guid.Empty); }
public async Task <IEnumerable <JsonPatchOperation> > Process(IMigrationContext migrationContext, IBatchMigrationContext batchContext, WorkItem sourceWorkItem, WorkItem targetWorkItem) { IList <JsonPatchOperation> jsonPatchOperations = new List <JsonPatchOperation>(); IEnumerable <WorkItemRelation> sourceRemoteLinks = sourceWorkItem.Relations?.Where(r => RelationHelpers.IsRemoteLinkType(migrationContext, r.Rel)); if (sourceRemoteLinks != null && sourceRemoteLinks.Any()) { foreach (WorkItemRelation sourceRemoteLink in sourceRemoteLinks) { string url = ConvertRemoteLinkToHyperlink(sourceRemoteLink.Url); WorkItemRelation targetRemoteLinkHyperlinkRelation = GetHyperlinkIfExistsOnTarget(targetWorkItem, url); if (targetRemoteLinkHyperlinkRelation != null) // is on target { JsonPatchOperation remoteLinkHyperlinkAddOperation = MigrationHelpers.GetRelationAddOperation(targetRemoteLinkHyperlinkRelation); jsonPatchOperations.Add(remoteLinkHyperlinkAddOperation); } else // is not on target { string comment = string.Empty; if (sourceRemoteLink.Attributes.ContainsKey(Constants.RelationAttributeComment)) { comment = $"{sourceRemoteLink.Attributes[Constants.RelationAttributeComment]}"; } WorkItemRelation newRemoteLinkHyperlinkRelation = new WorkItemRelation(); newRemoteLinkHyperlinkRelation.Rel = Constants.Hyperlink; newRemoteLinkHyperlinkRelation.Url = url; newRemoteLinkHyperlinkRelation.Attributes = new Dictionary <string, object>(); newRemoteLinkHyperlinkRelation.Attributes[Constants.RelationAttributeComment] = comment; JsonPatchOperation remoteLinkHyperlinkAddOperation = MigrationHelpers.GetRelationAddOperation(newRemoteLinkHyperlinkRelation); jsonPatchOperations.Add(remoteLinkHyperlinkAddOperation); } } } return(jsonPatchOperations); }
/// <summary>Gets the ID of the related item.</summary> /// <param name="source">The source.</param> /// <returns>The ID of the related item or 0 if it cannot be found.</returns> /// <remarks> /// The related ID isn't available directly but has to be determined by parsing the URL. Only work items are supported right now. /// </remarks> public static int GetRelatedId(this WorkItemRelation source) { //Parse the URL, the ID is the last value var url = source.Url; if (!String.IsNullOrEmpty(url)) { //Skip to the last value var idStringIndex = url.LastIndexOf('/'); if (idStringIndex >= 0) { var idString = url.Substring(idStringIndex + 1); if (Int32.TryParse(idString, out var id)) { return(id); } } ; } ; return(0); }
private async Task MigrateWorkItemGitCommitLinkAsync(MigrationContext context, IEnumerable <WorkItemRelation> relations, WorkItem targetItem, CancellationToken cancellationToken) { var doc = new JsonPatchDocument(); var targetRepositories = Settings.Repositories.ToDictionary(x => x.Source, x => x.Target); Regex regexSplitGitUrl = new Regex(@"^vstfs:\/\/\/git\/commit\/(?<projectId>[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})\/(?<repositoryId>[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})\/(?<commitId>[a-f0-9]{40})$", RegexOptions.IgnoreCase); var sourceGitCommitRelations = relations.Where(r => r.IsGitCommit()); foreach (var sourceGitCommit in sourceGitCommitRelations) { var gitCommitUrl = Uri.UnescapeDataString(sourceGitCommit.Url); var match = regexSplitGitUrl.Match(gitCommitUrl); if (match.Success && targetRepositories.TryGetValue(match.Groups["repositoryId"].Value, out string targetRepositoryId)) { var targetProject = await context.GetTargetProjectAsync(cancellationToken); var targetgitCommitUrl = regexSplitGitUrl.Replace(gitCommitUrl, m => $"Vstfs:///Git/Commit/{targetProject.Id}/{targetRepositoryId}/{m.Groups["commitId"].Value}"); WorkItemRelation targetGitCommit = new WorkItemRelation { Rel = sourceGitCommit.Rel, Attributes = sourceGitCommit.Attributes, Url = targetgitCommitUrl }; Logger.Debug($"Adding Git commit link {targetgitCommitUrl}"); doc.AddLink(targetGitCommit); } } //If we have made any changes then update the target if (doc.Any()) { await context.TargetService.UpdateWorkItemUnrestrictedAsync(targetItem, doc, cancellationToken).ConfigureAwait(false); } }
private void ProcessUpdatedSourceWorkItem(WorkItem targetWorkItem, WorkItemMigrationState workItemMigrationState, WorkItemRelation hyperlinkToSourceRelation) { //get the source rev from the revision dictionary - populated by PostValidateWorkitems int sourceId = workItemMigrationState.SourceId; int sourceRev = ValidationContext.SourceWorkItemRevision[sourceId]; string sourceUrl = ValidationContext.WorkItemIdsUris[sourceId]; int targetRev = GetRev(this.ValidationContext, targetWorkItem, sourceId, hyperlinkToSourceRelation); if (IsDifferenceInRevNumbers(sourceId, targetWorkItem, hyperlinkToSourceRelation, targetRev)) { Logger.LogInformation(LogDestination.File, $"Source workItem {sourceId} Rev {sourceRev} Target workitem {targetWorkItem.Id} Rev {targetRev}"); this.sourceWorkItemIdsThatHaveBeenUpdated.Add(sourceId); workItemMigrationState.Requirement |= WorkItemMigrationState.RequirementForExisting.UpdatePhase1; workItemMigrationState.Requirement |= WorkItemMigrationState.RequirementForExisting.UpdatePhase2; } else if (IsPhase2UpdateRequired(workItemMigrationState, targetWorkItem)) { workItemMigrationState.Requirement |= WorkItemMigrationState.RequirementForExisting.UpdatePhase2; } else { workItemMigrationState.Requirement |= WorkItemMigrationState.RequirementForExisting.None; } }
private void StoreTargetRelationPhaseStatusHyperlinkDataFromWorkItem(WorkItemMigrationState workItemMigrationState, WorkItemRelation hyperlinkToSourceRelation) { var targetAttributes = hyperlinkToSourceRelation.Attributes; targetAttributes.TryGetValue(Constants.RelationAttributeComment, out string targetRelationPhaseStatus); workItemMigrationState.RevAndPhaseStatus = new RevAndPhaseStatus(targetRelationPhaseStatus); }
private WorkItemRelation GetAttachmentIfExistsOnTarget(WorkItem targetWorkItem, WorkItemRelation sourceRelation) { if (targetWorkItem.Relations == null) { return(null); } foreach (WorkItemRelation targetRelation in targetWorkItem.Relations) { if (targetRelation.Rel.Equals(Constants.AttachedFile) && targetRelation.Url.Equals(sourceRelation.Url, StringComparison.OrdinalIgnoreCase)) { return(targetRelation); } } return(null); }
Staging FillSyncAllStagingTable(SystemToDbViewModel syncAllViewModel, WorkItem workItem, int systemId) { Staging staging = new Staging { RecordDateCreated = DateTime.Now, SystemId = systemId, ChangedFields = "all", RecordDateUpdated = DateTime.Now, RecordState = RecordStateConst.New, WebHookEvent = "syncAll" }; if (workItem.Fields.ContainsKey("System.TeamProject")) { staging.ProjectId = (string)workItem.Fields["System.TeamProject"]; staging.ProjectKey = (string)workItem.Fields["System.TeamProject"]; staging.ProjectName = (string)workItem.Fields["System.TeamProject"]; } staging.IssueId = workItem.Id?.ToString(); staging.IssueKey = workItem.Id?.ToString(); if (workItem.Fields.ContainsKey("System.WorkItemType")) { staging.IssueTypeId = workItem.Fields["System.WorkItemType"].ToString(); staging.IssueTypeName = workItem.Fields["System.WorkItemType"].ToString(); } if (workItem.Fields.ContainsKey("System.Title")) { staging.IssueName = workItem.Fields["System.Title"].ToString(); } if (workItem.Fields.ContainsKey("System.IterationId")) { staging.ParentVersionId = workItem.Fields["System.IterationId"].ToString(); } if (workItem.Fields.ContainsKey("System.IterationLevel2")) { staging.ParentVersionName = workItem.Fields["System.IterationLevel2"].ToString(); } if (workItem.Fields.ContainsKey("System.AssignedTo")) { if (workItem.Fields["System.AssignedTo"] != null) { staging.Assignee = workItem.Fields["System.AssignedTo"].ToString() .Substring(workItem.Fields["System.AssignedTo"].ToString() .IndexOf("<", StringComparison.Ordinal)).Trim('<', '>'); } } if (workItem.Relations != null) { WorkItemRelation relationCrt = workItem.Relations .FirstOrDefault(x => x.Rel == "System.LinkTypes.Hierarchy-Reverse"); if (relationCrt != null) { string parentKey = relationCrt.Url.Substring(relationCrt.Url.LastIndexOf("/", StringComparison.Ordinal) + 1); Staging parentStaging = syncAllViewModel.StagingsToInsert.FirstOrDefault(x => x.IssueKey == parentKey); if (parentStaging != null) { if (parentStaging.IssueTypeName == "Epic") { staging.ParentEpicId = parentKey; staging.ParentEpicKey = parentKey; } else { staging.ParentIssueId = parentKey; staging.ParentIssueKey = parentKey; } } } else { staging.ParentIssueId = null; staging.ParentIssueKey = null; } } syncAllViewModel.StagingsToInsert.Add(staging); return(staging); }
private async Task <AttachmentLink> UploadAttachmentFromSourceRelation(IMigrationContext migrationContext, IBatchMigrationContext batchContext, WorkItem sourceWorkItem, WorkItemRelation sourceRelation, int maxAttachmentSize) { //Attachments are of type Rel = "AttachedFile" if (sourceRelation.Rel == Constants.AttachedFile) { string filename = null; string comment = null; long resourceSize = 0; //get the file name and comment if (sourceRelation.Attributes.ContainsKey(Constants.RelationAttributeName)) { filename = sourceRelation.Attributes[Constants.RelationAttributeName].ToString(); } if (sourceRelation.Attributes.ContainsKey(Constants.RelationAttributeComment)) { comment = sourceRelation.Attributes[Constants.RelationAttributeComment].ToString(); } //get the guid from the url Guid attachmentId; if (Guid.TryParse(sourceRelation.Url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last(), out attachmentId)) { Stream stream = null; try { Logger.LogTrace(LogDestination.File, $"Reading attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); stream = await WorkItemTrackingHelpers.GetAttachmentAsync(migrationContext.SourceClient.WorkItemTrackingHttpClient, attachmentId); Logger.LogTrace(LogDestination.File, $"Completed reading attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); } catch (Exception e) { Logger.LogError(LogDestination.File, e, $"Unable to download attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentDownloadError, batchContext.WorkItemMigrationState); return(null); } AttachmentReference aRef = null; using (MemoryStream memstream = new MemoryStream()) { using (stream) { try { Logger.LogTrace(LogDestination.File, $"Downloading attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); await ClientHelpers.CopyStreamAsync(stream, memstream); Logger.LogTrace(LogDestination.File, $"Completed downloading attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); } catch (Exception e) { Logger.LogError(LogDestination.File, e, $"Unable to read downloaded attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentDownloadError, batchContext.WorkItemMigrationState); return(null); } } resourceSize = memstream.Length; if (resourceSize > maxAttachmentSize) { Logger.LogWarning(LogDestination.File, $"Attachment of source work item with id {sourceWorkItem.Id} and url {sourceRelation.Url} exceeded the maximum attachment size of {maxAttachmentSize} bytes." + $" Skipping creating the attachment in target account."); return(null); } memstream.Position = 0; //upload the attachment to the target try { Logger.LogTrace(LogDestination.File, $"Uploading attachment {filename} of {resourceSize} bytes for source work item {sourceWorkItem.Id} from the source account"); aRef = await WorkItemTrackingHelpers.CreateAttachmentChunkedAsync(migrationContext.TargetClient.WorkItemTrackingHttpClient, migrationContext.TargetClient.Connection, memstream, migrationContext.Config.AttachmentUploadChunkSize); Logger.LogTrace(LogDestination.File, $"Completed uploading attachment {filename} for source work item {sourceWorkItem.Id} from the source account"); } catch (Exception e) { Logger.LogError(LogDestination.File, e, $"Unable to upload attachment {filename} for source work item {sourceWorkItem.Id} to the target account"); ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentUploadError, batchContext.WorkItemMigrationState); } } if (aRef != null) { return(new AttachmentLink(filename, aRef, resourceSize, comment)); } } else { Logger.LogError(LogDestination.File, $"Attachment link is incorrect for {sourceWorkItem.Id} {sourceRelation.Url}. Skipping creating the attachment in target account."); ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentUploadError, batchContext.WorkItemMigrationState); } } return(null); }
private bool IsRelationAttachedFile(WorkItemRelation relation) { return(relation.Rel.Equals(Constants.AttachedFile, StringComparison.OrdinalIgnoreCase)); }
Master FillSyncAllMasterTable(SystemToDbViewModel syncAllViewModel, WorkItem workItem, int systemId) { Master master = new Master { RecordDateCreated = DateTime.Now, SystemId = systemId, RecordDateUpdated = DateTime.Now }; if (workItem.Fields.ContainsKey("System.TeamProject")) { master.ProjectId = (string)workItem.Fields["System.TeamProject"]; master.ProjectKey = (string)workItem.Fields["System.TeamProject"]; master.ProjectName = (string)workItem.Fields["System.TeamProject"]; } master.IssueId = workItem.Id?.ToString(); master.IssueKey = workItem.Id?.ToString(); if (workItem.Fields.ContainsKey("System.WorkItemType")) { master.IssueTypeId = workItem.Fields["System.WorkItemType"].ToString(); master.IssueTypeName = workItem.Fields["System.WorkItemType"].ToString(); } if (workItem.Fields.ContainsKey("System.Title")) { master.IssueName = workItem.Fields["System.Title"].ToString(); } if (workItem.Fields.ContainsKey("System.IterationId")) { master.ParentVersionId = workItem.Fields["System.IterationId"].ToString(); } if (workItem.Fields.ContainsKey("System.IterationLevel2")) { master.ParentVersionName = workItem.Fields["System.IterationLevel2"].ToString(); } if (workItem.Fields.ContainsKey("System.AssignedTo")) { if (workItem.Fields["System.AssignedTo"] != null) { master.Assignee = workItem.Fields["System.AssignedTo"].ToString() .Substring(workItem.Fields["System.AssignedTo"].ToString() .IndexOf("<", StringComparison.Ordinal)).Trim('<', '>'); } } if (workItem.Relations != null) { WorkItemRelation relationCrt = workItem.Relations .FirstOrDefault(x => x.Rel == "System.LinkTypes.Hierarchy-Reverse"); if (relationCrt != null) { if (workItem.Fields["System.WorkItemType"].ToString().ToLower().Equals("feature")) { master.ParentEpicId = relationCrt.Url.Substring(relationCrt.Url.LastIndexOf("/", StringComparison.Ordinal) + 1); master.ParentEpicKey = relationCrt.Url.Substring(relationCrt.Url.LastIndexOf("/", StringComparison.Ordinal) + 1); } else { master.ParentIssueId = relationCrt.Url.Substring(relationCrt.Url.LastIndexOf("/", StringComparison.Ordinal) + 1); master.ParentIssueKey = relationCrt.Url.Substring(relationCrt.Url.LastIndexOf("/", StringComparison.Ordinal) + 1); } } else { master.ParentIssueId = null; master.ParentIssueKey = null; } } syncAllViewModel.MastersToInsert.Add(master); return(master); }
internal WorkItemRelationWrapper(WorkItemRelation relation) : this(relation.Url) { _relation = relation; }
private bool IsDifferenceInRevNumbers(int sourceWorkItemId, WorkItem targetWorkItem, WorkItemRelation hyperlinkToSourceRelation, int targetRev) { int sourceRev = ValidationContext.SourceWorkItemRevision[sourceWorkItemId]; int targetWorkItemId = targetWorkItem.Id.Value; return(sourceRev != targetRev); }
public async Task <IActionResult> Post([FromBody] JObject payload) { PayloadViewModel vm = BuildPayloadViewModel(payload); //make sure pat is not empty, if it is, pull from appsettings vm.pat = _appSettings.Value.PersonalAccessToken; //if the event type is something other the updated, then lets just return an ok if (vm.eventType != "workitem.updated") { return(new OkResult()); } // create our azure devops connection Uri baseUri = new Uri("https://dev.azure.com/" + vm.organization); VssCredentials clientCredentials = new VssCredentials(new VssBasicCredential("username", vm.pat)); VssConnection vssConnection = new VssConnection(baseUri, clientCredentials); // load the work item posted WorkItem workItem = await _workItemRepo.GetWorkItem(vssConnection, vm.workItemId); // this should never happen, but if we can't load the work item from the id, then exit with error if (workItem == null) { return(new StandardResponseObjectResult("Error loading workitem '" + vm.workItemId + "'", StatusCodes.Status500InternalServerError)); } // get the related parent WorkItemRelation parentRelation = workItem.Relations.Where <WorkItemRelation>(x => x.Rel.Equals("System.LinkTypes.Hierarchy-Reverse")).FirstOrDefault(); // if we don't have any parents to worry about, then just abort if (parentRelation == null) { return(new OkResult()); } Int32 parentId = _helper.GetWorkItemIdFromUrl(parentRelation.Url); WorkItem parentWorkItem = await _workItemRepo.GetWorkItem(vssConnection, parentId); if (parentWorkItem == null) { return(new StandardResponseObjectResult("Error loading parent work item '" + parentId.ToString() + "'", StatusCodes.Status500InternalServerError)); } string parentState = parentWorkItem.Fields["System.State"] == null ? string.Empty : parentWorkItem.Fields["System.State"].ToString(); // load rules for updated work item RulesModel rulesModel = _rulesRepo.ListRules(vm.workItemType); //loop through each rule foreach (var rule in rulesModel.Rules) { if (rule.IfChildState.Equals(vm.state)) { if (!rule.AllChildren) { if (!rule.NotParentStates.Contains(parentState)) { await _workItemRepo.UpdateWorkItemState(vssConnection, parentWorkItem, rule.SetParentStateTo); return(new OkResult()); } } else { // get a list of all the child items to see if they are all closed or not List <WorkItem> childWorkItems = await _workItemRepo.ListChildWorkItemsForParent(vssConnection, parentWorkItem); // check to see if any of the child items are not closed, if so, we will get a count > 0 int count = childWorkItems.Where(x => !x.Fields["System.State"].ToString().Equals(rule.IfChildState)).ToList().Count; if (count.Equals(0)) { await _workItemRepo.UpdateWorkItemState(vssConnection, parentWorkItem, rule.SetParentStateTo); } return(new OkResult()); } } } return(new StandardResponseObjectResult("success", StatusCodes.Status200OK)); }
private int GetRev(IValidationContext context, WorkItem targetWorkItem, int sourceWorkItemId, WorkItemRelation hyperlinkToSourceRelation) { var targetAttributes = hyperlinkToSourceRelation.Attributes; targetAttributes.TryGetValue(Constants.RelationAttributeComment, out string targetRelationPhaseStatus); string revNumberString = targetRelationPhaseStatus.SplitBySemicolonToHashSet().First(); return(Convert.ToInt32(revNumberString)); }