/// <summary> /// Process Attachments and Links creation. Has to be at the end /// </summary> /// <param name="imWorkItem"></param> /// <param name="setMigStatus"></param> private bool ProcessAttachmentsAndLinks(InMemoryWorkItem imWorkItem, bool setMigStatus) { bool retVal = true; Logger.Write(LogSource.WorkItemTracking, TraceLevel.Verbose, "[{0}] attachments for work item [{1}]", imWorkItem.Attachments.Count, m_sourceWorkItemId); Logger.Write(LogSource.WorkItemTracking, TraceLevel.Verbose, "[{0}] links for work item [{1}]", imWorkItem.Links.Count, m_sourceWorkItemId); try { // create new web service call xml fragment WSHelper webServiceHelper = new WSHelper(WSHelper.WebServiceType.UpdateWorkItem); webServiceHelper.SetWorkItemAndRevision(m_currentWorkItem.Id, ++m_revision); // process links if (imWorkItem.Links.Count > 0) { foreach (InMemoryLinkItem imLink in imWorkItem.Links) { if (!IsLinkMigrated(imLink)) { if (imLink.CurrituckLinkedId == -1) { // link cannot be set as well as description cannot be found in history webServiceHelper.AddDescriptiveField(VSTSConstants.HistoryFieldRefName, String.Concat(VSTSUtil.ConverterComment, imLink.LinkDescription), true); } else { // set the link information in work item.. as a related link webServiceHelper.AddLink(imLink.CurrituckLinkedId, imLink.LinkDescription); // check if it is duplicate link and setting Duplicate WI is allowed if (m_canSetDuplicateWiId && imLink is InMemoryDuplicateLinkItem && m_vstsConnection.store.FieldDefinitions.Contains(m_duplicateWiId)) { Logger.Write(LogSource.WorkItemTracking, TraceLevel.Info, "Creating Duplicate Link as Related Link from {0} to {1} with comment {2}", m_currentWorkItem.Id, imLink.CurrituckLinkedId, imLink.LinkDescription); webServiceHelper.AddColumn(m_wi.Fields[m_duplicateWiId].ReferenceName, imLink.CurrituckLinkedId.ToString(CultureInfo.InvariantCulture)); } } // end of else } // end of isLinkMigrated() else { Logger.Write(LogSource.WorkItemTracking, TraceLevel.Warning, "Cannot add link as it already exists: {0}", imLink.CurrituckLinkedId); } } } // process attachments if (imWorkItem.Attachments.Count > 0) { int noOfAttachmentsProcessed = 0; string areaNodeUri = GetAreaNodeUri(m_vstsWorkItem.areaId); Debug.Assert(!String.IsNullOrEmpty(areaNodeUri), "No area node uri found"); foreach (InMemoryAttachment attach in imWorkItem.Attachments) { if (IsAttachmentMigrated(attach)) { continue; } try { webServiceHelper.AddAttachment(attach.FileName, attach.Comment, attach.IsLinkedFile, areaNodeUri); } catch (ConverterException conEx) { // attachment upload failed.. add into migration report string errMsg = UtilityMethods.Format( VSTSResource.VstsAttachmentUploadFailed, Path.GetFileName(attach.FileName), m_sourceWorkItemId, conEx.Message); ConverterMain.MigrationReport.WriteIssue(String.Empty, ReportIssueType.Error, errMsg, m_sourceWorkItemId.ToString(CultureInfo.InvariantCulture)); Display.DisplayError(errMsg); // and make sure that Migration Status is not set setMigStatus = false; retVal = false; } noOfAttachmentsProcessed++; if (noOfAttachmentsProcessed % 32 == 0) { // save at every 32nd attachment webServiceHelper.AddDescriptiveField( VSTSConstants.HistoryFieldRefName, UtilityMethods.Format( VSTSResource.VstsAttachmentLinkHistory), true); Logger.Write(LogSource.WorkItemTracking, TraceLevel.Warning, "Performing interim save for work item {0} since no of attachments exceeds 32", m_sourceWorkItemId); if (imWorkItem.Attachments.Count == noOfAttachmentsProcessed) { // boundary case .. this is the last attachment.. // set the Migration Status also if (setMigStatus) { webServiceHelper.AddColumn(VSTSConstants.MigrationStatusField, "Done"); } } webServiceHelper.Save(); if (noOfAttachmentsProcessed < imWorkItem.Attachments.Count) { // some attachemnts left.. reset the webserviceHelper handle webServiceHelper = new WSHelper(WSHelper.WebServiceType.UpdateWorkItem); webServiceHelper.SetWorkItemAndRevision(m_currentWorkItem.Id, ++m_revision); } else { // no more save required for the current work item webServiceHelper = null; } } // end of if (noOfAttachmentsProcessed % 32 == 0) } // end of foreach attachments } if (webServiceHelper != null) { webServiceHelper.AddDescriptiveField( VSTSConstants.HistoryFieldRefName, UtilityMethods.Format( VSTSResource.VstsAttachmentLinkHistory), true); // Set migration status field if (setMigStatus) { webServiceHelper.AddColumn(VSTSConstants.MigrationStatusField, "Done"); } webServiceHelper.Save(); } SetCurrentWorkItem(m_currentWorkItem.Id); } finally { } return(retVal); }
/// <summary> /// Create work item in the Currituck corresponding to the given memory work item /// </summary> /// <param name="sourceWIId">Source Work Item ID</param> /// <param name="imWorkItem">In Memory Work Item containing Initial View, Attachments and Links</param> /// <param name="setMigStatus">Set the Migration Status field to Done or not</param> /// <returns>true if it is able to save all fields, attachments and links, else false</returns> public bool CreateInitialViewOfWorkItem(string sourceWIId, InMemoryWorkItem imWorkItem, bool setMigStatusDone) { bool retVal = true; m_vstsWorkItem = new VSTSWorkItem(); try { m_sourceWorkItemId = sourceWIId; m_vstsWorkItem.sourceId = sourceWIId; // create new webs service call xml fragment WSHelper webServiceHelper = new WSHelper(WSHelper.WebServiceType.InsertWorkItem); // push the initial snapshot IDictionaryEnumerator enumerator = m_baseWiSnapShot.GetEnumerator(); while (enumerator.MoveNext()) { webServiceHelper.AddColumn(enumerator.Key.ToString(), enumerator.Value.ToString()); } // set the default value of area id to root node initially m_vstsWorkItem.areaId = m_wi.AreaId; // first set the initial required fields.. if some save happens in // state processing, bug will be created with minimal information foreach (string fldName in VSTSUtil.InitialFields[m_convSourceIndex]) { if (imWorkItem.InitialView[fldName] != null) { UpdateWorkItemField(webServiceHelper, fldName, imWorkItem.InitialView[fldName]); } } // while creating initial view the fields with no values does not // makes any sense... they are required for further revisions where // the values would have been removed.. // filter the initial view to remove all the null values ArrayList nullFields = new ArrayList(); foreach (DictionaryEntry de in imWorkItem.InitialView) { if (de.Value == null) { nullFields.Add(de.Key); } else { // see if it is empty string if (de.Value is string) { if (String.IsNullOrEmpty((string)de.Value)) { nullFields.Add(de.Key); } } } } foreach (object toRemove in nullFields) { imWorkItem.InitialView.Remove(toRemove); } ProcessRevision(webServiceHelper, imWorkItem.InitialView, "0"); // Set migration status field only if no links and attachments exist if (setMigStatusDone && imWorkItem.Attachments.Count == 0 && imWorkItem.Links.Count == 0) { // completed the migration for initial view webServiceHelper.AddColumn(VSTSConstants.MigrationStatusField, "Done"); } int workItemId = webServiceHelper.Save(); Debug.Assert(workItemId != 0, "Work Item save returned ID as 0"); // set the m_currentworkitem context m_currentWorkItem = SetCurrentWorkItem(workItemId); m_revision = m_currentWorkItem.Rev - 1; m_vstsWorkItem.Id = workItemId; } finally { } // process attachments and links only if SetMigStatus is true.. // i.e. this is the only revision to be created if (setMigStatusDone && (imWorkItem.Attachments.Count > 0 || imWorkItem.Links.Count > 0)) { retVal = ProcessAttachmentsAndLinks(imWorkItem, setMigStatusDone); } Logger.Write(LogSource.WorkItemTracking, TraceLevel.Verbose, "Created new work item : {0}", m_currentWorkItem.Id); return(retVal); }
/// <summary> /// Add/Update the web service package with the given field and value /// </summary> /// <param name="webServiceHelper">Web Service package</param> /// <param name="fName">Field Name</param> /// <param name="fValue">Field Value</param> internal void UpdateWorkItemField(WSHelper webServiceHelper, string fName, object fValue) { if (fValue == null || fValue.ToString().Trim().Length == 0) { fValue = String.Empty; } // apply field map and value map string toFldName = GetMappedFieldName(fName, ref fValue); if (string.IsNullOrEmpty(toFldName)) { Logger.Write(LogSource.WorkItemTracking, TraceLevel.Info, "No field map for work item [{0}], field [{1}].. Dropping", m_sourceWorkItemId, fName); return; } Field fld = m_wi.Fields[toFldName]; if (fld != null) { if (VSTSConstants.SkipFields.ContainsKey(fld.ReferenceName)) { Logger.Write(LogSource.WorkItemTracking, TraceLevel.Info, "Field {0} is being skipped as it cannot be modified using web service", fName); return; } switch (fld.FieldDefinition.FieldType) { // html type fields case CurClient.FieldType.Html: case CurClient.FieldType.History: // apply html formatting on this // and add to InsertText webServiceHelper.AddDescriptiveField(fld.ReferenceName, VSTSUtil.ConvertTextToHtml(fValue.ToString()), true); break; case CurClient.FieldType.PlainText: // add to InsertText webServiceHelper.AddDescriptiveField(fld.ReferenceName, fValue.ToString(), false); break; case CurClient.FieldType.DateTime: DateTime value; string dateValue = String.Empty; if (fValue is DateTime) { value = (DateTime)fValue; dateValue = CommonConstants.ConvertDateToString(value); } else { if (!String.IsNullOrEmpty(fValue.ToString())) { Logger.Write(LogSource.WorkItemTracking, TraceLevel.Warning, "Value of field {0} is not of type DateTime", fld.Name, fValue.ToString()); if (DateTime.TryParse(fValue.ToString(), out value) == true) { dateValue = CommonConstants.ConvertDateToString(value); } } } webServiceHelper.AddColumn(fld.ReferenceName, dateValue); break; case CurClient.FieldType.String: string fStrVal = fValue.ToString(); string fTruncatedValue = fStrVal; if (fStrVal.Length > VSTSConstants.MaxStringFieldLength) { // put the original value in history field webServiceHelper.AddDescriptiveField(VSTSConstants.HistoryFieldRefName, String.Concat(toFldName, ": ", fStrVal), true); // Fix for 58661 CQConverter: The truncation of string fields should // be reported in the migration report. string warnMsg = string.Format(VSTSResource.WarningFieldTruncated, toFldName, fStrVal, fTruncatedValue); ConverterMain.MigrationReport.WriteIssue(String.Empty, warnMsg, m_sourceWorkItemId.ToString(CultureInfo.InvariantCulture), string.Empty, IssueGroup.Wi.ToString(), ReportIssueType.Warning, null); // truncate the field value fTruncatedValue = fStrVal.Substring(0, VSTSConstants.MaxStringFieldLength); Logger.Write(LogSource.WorkItemTracking, TraceLevel.Warning, "Truncating field '{0}' value , From [{1}] to [{2}]", toFldName, fStrVal, fTruncatedValue); } webServiceHelper.AddColumn(fld.ReferenceName, fTruncatedValue); break; default: webServiceHelper.AddColumn(fld.ReferenceName, fValue.ToString()); break; } } }