/// <summary>
        /// Creates a work item in memory.
        /// </summary>
        /// <param name="title">Work item title.</param>
        public int CreateWorkItem(string title)
        {
            var workItem = new InMemoryWorkItem {
                Title = title
            };

            this.workItems.Add(workItem);

            return(workItem.Id);
        }
        /// <inheritdoc/>
        public TfsWorkItem GetWorkItemForIssue(string issueId, int issueActivityCount)
        {
            bool isNew = false;

            if (string.IsNullOrEmpty(issueId))
            {
                throw new ArgumentNullException(nameof(issueId));
            }

            if (this.parentWorkItemId == -1)
            {
                throw new Exception("Please run ConfigureAsync first.");
            }

            var hasChange      = false;
            var parentWorkItem = this.workItems.Single(w => w.Id == this.parentWorkItemId);

            string[] commentParts = null;
            var      workItemLink = parentWorkItem.Links.FirstOrDefault(l =>
            {
                if (l.Comment.StartsWith(issueId))
                {
                    commentParts = l.Comment.Split(':');
                    return(true);
                }

                return(false);
            });
            InMemoryWorkItem workItem = null;

            if (workItemLink != null)
            {
                if (!commentParts[1].Equals(issueActivityCount.ToString(CultureInfo.InvariantCulture)))
                {
                    hasChange = true;
                }

                workItem = this.workItems.Single(w => w.Id == workItemLink.RelatedWorkItemId);
            }
            else
            {
                workItem  = new InMemoryWorkItem();
                hasChange = true;
                isNew     = true;
            }

            var issueSignature = $"{issueId}:{issueActivityCount}";
            var imtw           = new InMemoryTfsWorkItem(workItem)
            {
                HasChange = hasChange, IssueSignature = issueSignature
            };

            imtw.IsNew = isNew;
            return(imtw);
        }
Example #3
0
        /// <summary>
        /// Process all the history revisions
        /// </summary>
        /// <param name="sourceWIId"></param>
        /// <param name="imWorkItem"></param>
        /// <param name="setMigStatusDone"></param>
        /// <returns></returns>
        public bool WriteHistoryItems(string sourceWIId, InMemoryWorkItem imWorkItem, bool setMigStatusDone)
        {
            m_revision            = m_currentWorkItem.Rev - 1;
            m_vstsWorkItem.Id     = m_currentWorkItem.Id;
            m_vstsWorkItem.areaId = m_currentWorkItem.AreaId;

            m_sourceWorkItemId = sourceWIId;
            string currentMigStatus = (string)m_currentWorkItem[m_migrationStatusFieldName];
            int    revCount         = 0;
            bool   isMigStatusInt   = int.TryParse(currentMigStatus, out revCount);

            Debug.Assert(isMigStatusInt); // should be able to parse always.. otherwise a code bug

            // process all history revisions and save in each call
            for (int historyIdx = 0; historyIdx < imWorkItem.HistoryItems.Count; historyIdx++)
            {
                // create new webs service call xml fragment
                WSHelper webServiceHelper = new WSHelper(WSHelper.WebServiceType.UpdateWorkItem);

                // set the required attributes
                webServiceHelper.SetWorkItemAndRevision(m_currentWorkItem.Id, ++m_revision);

                InMemoryHistoryItem imHistoryItem = (InMemoryHistoryItem)imWorkItem.HistoryItems[historyIdx];

                if (historyIdx == imWorkItem.HistoryItems.Count - 1 && // last history item
                    imWorkItem.Attachments.Count == 0 &&               // no attachments
                    imWorkItem.Links.Count == 0 &&                     // no links
                    setMigStatusDone)                                  // caller asked for it
                {
                    // last item.. set mig status to done
                    ProcessRevision(webServiceHelper, imHistoryItem.UpdatedView, "Done");
                }
                else
                {
                    ProcessRevision(webServiceHelper, imHistoryItem.UpdatedView, (++revCount).ToString());
                }

                try
                {
                    webServiceHelper.Save();
                }
                finally
                {
                }
            }

            if (imWorkItem.Attachments.Count > 0 ||
                imWorkItem.Links.Count > 0)
            {
                return(ProcessAttachmentsAndLinks(imWorkItem, setMigStatusDone));
            }

            return(true);
        }
Example #4
0
        } // end of CQEntityRec CTor

        /// <summary>
        /// Populate the current record from CQ if its not already in Currituck
        /// and also process all its references (recursively), Links, History and Attachments
        /// Else just sets the currituck id for future reference
        /// </summary>
        public bool Populate()
        {
            bool partiallyMigrated = false;
            // first check if it exists in the memory cache
            CQEntity    currentEntityRecords = m_cqParams.entityRecords[m_entityName];
            CQEntityRec lookupEntity         = currentEntityRecords.FindEntityRec(m_entityName, m_dbid);

            if (lookupEntity != null)
            {
                // record already populated..
                Logger.Write(LogSource.CQ, TraceLevel.Verbose, "Already populated record '{0}' for Entity '{1}', DBID:{2}",
                             lookupEntity.SourceId, lookupEntity.EntityName, lookupEntity.DBID);
                return(true);
            }

            m_CQEntity = CQWrapper.GetEntityByDbId(m_cqParams.cqSession, m_entityName, m_dbid);

            // get the source id
            m_sourceId = CQWrapper.GetEntityDisplayName(m_CQEntity);
            Logger.Write(LogSource.CQ, TraceLevel.Verbose, UtilityMethods.Format(CQResource.CQ_PROCESSING_REC, m_sourceId));

            // check if it exist in currituck using static API
            VSTSWorkItemHelper wiHelper  = (VSTSWorkItemHelper)m_MySchemaMap.vstsHelper;
            ArrayList          checkList = new ArrayList();

            checkList.Add(new WorkItemNameValueRelation(CommonConstants.VSTSSrcIdField, m_sourceId));
            checkList.Add(new WorkItemNameValueRelation(CommonConstants.VSTSSrcDbField, m_cqParams.uniqueInstId));

            wiHelper = (VSTSWorkItemHelper)m_MySchemaMap.vstsHelper;
            if (wiHelper.IsWIMigrated(checkList) == true)
            {
                // need not to load the data from CQ..
                // just set the currituck id
                // not going to update this bug from CQ->Currituck even
                // if it is updated.. just get out from here as my population is done
                // with minimal required stuff
                string warningMsg = UtilityMethods.Format(CQResource.CQ_REC_MIGRATED, m_sourceId);
                Logger.Write(LogSource.CQ, TraceLevel.Warning, warningMsg);
                PostMigrationReport.WriteIssue(m_MySchemaMap.entity, m_MySchemaMap.WIT,
                                               Stats.MigrationStatus.Skipped,
                                               ReportIssueType.Warning,
                                               String.Empty,
                                               m_sourceId, IssueGroup.Wi, warningMsg);

                m_WITId = wiHelper.WorkItemId;
                //compact current object
                CompactMe();
                return(true);
            }
            else if (wiHelper.IsCurrentWorkItemValid() == true)
            {
                // work item is already there.. partially migrated
                partiallyMigrated = true;
            }

#if DEBUG
            CommonConstants.NoOfBugs++;
#endif
            // create the required data structures
            m_imWorkItem = new InMemoryWorkItem();
            string fldName;

            OAdEntityDef curEntityDef = CQWrapper.GetEntityDef(m_cqParams.cqSession, m_entityName);
            Logger.Write(LogSource.CQ, TraceLevel.Verbose, "Adding record for Entity {0}, Record {1}",
                         m_entityName, CQWrapper.GetEntityDisplayName(m_CQEntity));

            object[] fields = (object[])CQWrapper.GetEntityFieldNames(m_CQEntity);
            foreach (object fld in fields)
            {
                fldName = (string)fld;
                if (CQConstants.InternalFieldTypes.ContainsKey(fldName))
                {
                    // these are internal clearquest fields
                    // we dont want to migrate these
                    Logger.Write(LogSource.CQ, TraceLevel.Info, "Skipping Internal Field '{0}' while migrating data for entity {1}",
                                 fldName, m_entityName);
                    continue;
                }
                {
                    // process this field only if it exists in the "from" side of Field Map
                    OAdFieldInfo fldInfo     = CQWrapper.GetEntityFieldValue(m_CQEntity, fldName);
                    int          cqFieldType = CQWrapper.GetFieldType(fldInfo);

                    switch (cqFieldType)
                    {
                    case CQConstants.FIELD_ID:
                    case CQConstants.FIELD_SHORT_STRING:
                    case CQConstants.FIELD_INT:
                    {
                        string fldValue = CQWrapper.GetFieldValue(fldInfo);
                        if (fldValue != null)
                        {
                            m_imWorkItem.InitialView.Add(fldName, fldValue);
                        }
                    }
                    break;

                    case CQConstants.FIELD_MULTILINE_STRING:
                    {
                        string fldValue = CQWrapper.GetFieldValue(fldInfo);
                        if (currentEntityRecords.Entity == null)
                        {
                            // build entity to get the list of allowed/suggested values
                            currentEntityRecords.Entity = CQWrapper.BuildEntity(m_cqParams.cqSession, currentEntityRecords.EntityName);
                        }
                        object[] choices = (object[])CQWrapper.GetFieldChoiceList(currentEntityRecords.Entity, fldName);
                        if (choices != null && choices.Length > 0)
                        {
                            // Multi Line String with List of Allowed/Suggested Values.. replace all '\n' with comma
                            // fix for bug# 429098
                            if (fldValue != null)
                            {
                                fldValue = fldValue.Replace("\n", ",");
                            }
                        }

                        /* no conversion shall be required.. bug# 20219 - shall be rendered in HTML as it is
                         *  // hack for Notes_Log & Description field.. Shall be converted to HTML (bug#429032)
                         *  if (fldName.Equals("Notes_Log", StringComparison.OrdinalIgnoreCase) ||
                         *      fldName.Equals("Description", StringComparison.OrdinalIgnoreCase))
                         *  {
                         *      fldValue = VSTSUtil.ConvertTextToHtml(fldValue);
                         *  }
                         */
                        m_imWorkItem.InitialView.Add(fldName, fldValue);
                    }
                    break;

                    case CQConstants.FIELD_DATE_TIME:
                    {
                        string fldValue = CQWrapper.GetFieldValue(fldInfo);
                        if (fldValue != null)
                        {
                            // the time returned from CQ API is the local time..
                            DateTime fldVal = DateTime.Parse(fldValue, CultureInfo.CurrentCulture);

                            //convert it in UTC
                            DateTime utcTime = CQConverterUtil.ConvertLocalToUTC(fldVal);
                            Logger.Write(LogSource.CQ, TraceLevel.Verbose,
                                         "Field [{0}], CQ Time [{1}], UTC Time [{2}]",
                                         fldName, fldVal.ToString(), utcTime.ToString());

                            m_imWorkItem.InitialView.Add(fldName, utcTime);
                        }
                        else
                        {
                            Logger.Write(LogSource.CQ, TraceLevel.Info, "Got null value for field {0}", fldName);
                        }
                    }
                    break;

                    case CQConstants.FIELD_REFERENCE:
                    {
                        // get the current entity def handle
                        OAdEntityDef refEntityDef  = CQWrapper.GetFieldReferenceEntityDef(curEntityDef, fldName);
                        string       refEntityName = CQWrapper.GetEntityDefName(refEntityDef);

                        // special handling for users.. add the user field value also..
                        // we dont want to create a link in this case..
                        // just add the field value pair in IMWorkItem.. and
                        // user map will be applied while saving
                        if (TFStringComparer.WorkItemType.Equals(refEntityName, "users"))
                        {
                            if (CQWrapper.GetFieldValueStatus(fldInfo) == (int)CQConstants.FieldStatus.HAS_VALUE)
                            {
                                // single value required
                                string refFldVal = CQWrapper.GetFieldValue(fldInfo);
                                m_imWorkItem.InitialView.Add(fldName, refFldVal);
                            }
                        }
                        else if (m_cqParams.allowedEntities.ContainsKey(refEntityName))
                        {
                            int valueStatus = CQWrapper.GetFieldValueStatus(fldInfo);
                            Logger.WriteIf((valueStatus != (int)CQConstants.FieldStatus.HAS_VALUE), LogSource.CQ,
                                           TraceLevel.Info, "No Value for Referenced field {0} in Entity {1}",
                                           refEntityName, m_entityName);
                            if (valueStatus == (int)CQConstants.FieldStatus.HAS_VALUE)
                            {
                                // single value required
                                string refFldVal = CQWrapper.GetFieldValue(fldInfo);
                                if (String.Equals(refFldVal, SourceId, StringComparison.Ordinal))
                                {
                                    // reference to self.. cannot have a link on to self
                                    string warningMsg = UtilityMethods.Format(CQResource.CQ_SELF_REFERENCE, SourceId, EntityName, fldName);
                                    Logger.Write(LogSource.CQ, TraceLevel.Warning, warningMsg);
                                    PostMigrationReport.WriteIssue(m_MySchemaMap.entity, m_MySchemaMap.WIT,
                                                                   Stats.MigrationStatus.Warning,
                                                                   ReportIssueType.Warning,
                                                                   String.Empty,
                                                                   m_sourceId, IssueGroup.Wi, warningMsg
                                                                   );
                                }
                                else
                                {
                                    m_referencedEntities.Add(new LinkRecord(refEntityName, refFldVal));
                                }
                            }
                        }
                    }
                    break;

                    case CQConstants.FIELD_REFERENCE_LIST:
                    {
                        // get the current entity def handle
                        OAdEntityDef refEntityDef  = CQWrapper.GetFieldReferenceEntityDef(curEntityDef, fldName);
                        string       refEntityName = CQWrapper.GetEntityDefName(refEntityDef);
                        // special handling for user list
                        // we dont want to create a link in this case..
                        // concatenate all the user names separated by comma
                        // NO USER MAP WILL BE APPLIED WHILE SAVING (bug#400276)
                        if (TFStringComparer.WorkItemType.Equals(refEntityName, "users"))
                        {
                            if (CQWrapper.GetFieldValueStatus(fldInfo) == (int)CQConstants.FieldStatus.HAS_VALUE)
                            {
                                object[]      refFldValues = CQWrapper.GetFieldValueAsList(fldInfo);
                                StringBuilder userList     = new StringBuilder();
                                for (int valueIndex = 0; valueIndex < refFldValues.Length; valueIndex++)
                                {
                                    object refFldObj = refFldValues[valueIndex];
                                    if (valueIndex > 0)
                                    {
                                        userList.Append(",");
                                    }

                                    userList.Append((string)refFldObj);
                                }
                                m_imWorkItem.InitialView.Add(fldName, userList.ToString());
                            }
                        }
                        else if (m_cqParams.allowedEntities.ContainsKey(refEntityName))
                        {
                            int valueStatus = CQWrapper.GetFieldValueStatus(fldInfo);
                            Logger.WriteIf((valueStatus != (int)CQConstants.FieldStatus.HAS_VALUE), LogSource.CQ,
                                           TraceLevel.Info, "No Value for Referenced field {0} in Entity {1}",
                                           fldName, m_entityName);
                            if (valueStatus == (int)CQConstants.FieldStatus.HAS_VALUE)
                            {
                                // value list expected
                                object[] refFldValues = CQWrapper.GetFieldValueAsList(fldInfo);
                                foreach (object refFldObj in refFldValues)
                                {
                                    string refFldVal = (string)refFldObj;
                                    if (String.Equals(refFldVal, SourceId, StringComparison.Ordinal))
                                    {
                                        // reference to self.. cannot have a link on to self
                                        string warningMsg = UtilityMethods.Format(CQResource.CQ_SELF_REFERENCE, SourceId, EntityName, fldName);
                                        Logger.Write(LogSource.CQ, TraceLevel.Warning, warningMsg);
                                        PostMigrationReport.WriteIssue(m_MySchemaMap.entity, m_MySchemaMap.WIT,
                                                                       Stats.MigrationStatus.Warning,
                                                                       ReportIssueType.Warning,
                                                                       String.Empty,
                                                                       m_sourceId, IssueGroup.Wi, warningMsg);
                                    }
                                    else
                                    {
                                        m_referencedEntities.Add(new LinkRecord(refEntityName, refFldVal));
                                    }
                                }
                            }
                        }
                    }
                    break;

                    case CQConstants.FIELD_ATTACHMENT_LIST:
                    case CQConstants.FIELD_STATE:
                    case CQConstants.FIELD_JOURNAL:
                    case CQConstants.FIELD_DBID:
                    case CQConstants.FIELD_STATETYPE:
                    case CQConstants.FIELD_RECORDTYPE:
                        Logger.Write(LogSource.CQ, TraceLevel.Info, "Skipping the Field migration for Internal Field Type '{0}'",
                                     cqFieldType);
                        // not migrating these fields as they are CQ internal fields
                        continue;

                    default:
                        Logger.Write(LogSource.CQ, TraceLevel.Info, "Skipping the Field migration for Unkknown Field Type '{0}'",
                                     cqFieldType);
                        break;
                    }
                }
            } // end of foreachfields

            // add the source id and db separately
            m_imWorkItem.InitialView.Add(CommonConstants.VSTSSrcIdField, m_sourceId);
            m_imWorkItem.InitialView.Add(CommonConstants.VSTSSrcDbField, m_cqParams.uniqueInstId);

            // use vstshelper to migrate the data
            wiHelper = (VSTSWorkItemHelper)m_MySchemaMap.vstsHelper;
            wiHelper.IsWIMigrated(checkList);

            // get attachments in the imworkitem
            ProcessAttachments();

            // history processing will use same imWorkItem for first history info
            // and create other history indexes
            int migratedHistory = 0;
            if (wiHelper.IsCurrentWorkItemValid())
            {
                migratedHistory = wiHelper.GetCurrentWorkItemHistoryCount();
                if (migratedHistory > 0)
                {
                    // We are going for incremental migration. And as we stuff first history item of a CQBug
                    // into InitialView itself, actual no. of migrated history is one more than the value of
                    // the "Migration Status" field. So increment by one.
                    ++migratedHistory;
                }
            }

            ArrayList historyItems = ProcessHistory(m_imWorkItem.InitialView, migratedHistory);

            Logger.Write(LogSource.CQ, TraceLevel.Verbose, "Dumping initial view for {0}", m_sourceId);
            foreach (object key in m_imWorkItem.InitialView.Keys)
            {
                Logger.Write(LogSource.CQ, TraceLevel.Verbose, "{0} - {1}", key, m_imWorkItem.InitialView[key]);
            }

            bool initialViewStatus = true;
            try
            {
                if (!partiallyMigrated)
                {
                    // if some history items or links are left to be migrated.. leave the bug as opened..
                    if (historyItems.Count > 0 || m_referencedEntities.Count > 0)
                    {
                        Logger.Write(LogSource.CQ, TraceLevel.Verbose, "Creating initial view of {0} .. {1} Histories, {2} Links pending",
                                     SourceId, historyItems.Count, m_referencedEntities.Count);
                        // create the record and keep it open for history editing
                        initialViewStatus = wiHelper.CreateInitialViewOfWorkItem(m_sourceId, m_imWorkItem, false);
                    }
                    else
                    {
                        Logger.Write(LogSource.CQ, TraceLevel.Verbose, "Creating initial view of {0}", SourceId);
                        // create all the entries in the record and set the status to done
                        initialViewStatus = wiHelper.CreateInitialViewOfWorkItem(m_sourceId, m_imWorkItem, true);
                    }
                }
            }
            catch (Exception ex)
            {
                // creation of work item failed
                string errMsg = UtilityMethods.Format(CQResource.CQ_WI_CREATION_FAILED, SourceId, ex.Message);
                CQConverter.ReportWorkItemFailure(errMsg, SourceId, m_MySchemaMap.entity, m_MySchemaMap.WIT,
                                                  m_cqParams.exitOnError);
                if (m_cqParams.exitOnError == true)
                {
                    throw new ConverterException(errMsg);
                }
                else
                {
                    // continue with another work item
                    // need to skip this work item..
                    m_WITId = -1;
                    CompactMe();
                    return(false);
                }
            }
            finally
            {
            }

            // get back currituck id and store in this
            m_WITId = wiHelper.WorkItemId;

            // store the handle of work item to restore the state of work item helper back to
            // working work item which may get changed because of processing links recursively
            object workItem = wiHelper.GetCurrentWorkItem();

            // before processing history, clean out attachments.. only if its already migrated
            if (wiHelper.GetCurrentWorkItemAttachmentsCount() == m_imWorkItem.Attachments.Count)
            {
                m_imWorkItem.Attachments.Clear();
            }

            // add all the links now so that they go as part of history
            bool refRecordStatus = true;
            foreach (LinkRecord linkRec in m_referencedEntities)
            {
                if (AddReferenceRecord(linkRec) == false)
                {
                    refRecordStatus = false; // once false always false
                }
            }

            // process duplicate records
            if (ProcessDuplicates(m_cqParams) == false)
            {
                refRecordStatus = false;
            }

            bool writeHistoryPassed = true;
            wiHelper.SetCurrentWorkItem(workItem);
            if (historyItems.Count > 0 || m_imWorkItem.Links.Count > 0 || m_imWorkItem.Attachments.Count > 0)
            {
                m_imWorkItem.HistoryItems = historyItems;

                try
                {
                    writeHistoryPassed = wiHelper.WriteHistoryItems(m_sourceId, m_imWorkItem,
                                                                    refRecordStatus && initialViewStatus);
                    if (!writeHistoryPassed)
                    {
                        // Bug#59861: In the case of the partially migrated bug,
                        // converter says all bugs migrated successfully in
                        // summary, but in error section it says one bug  failed
                        // due to attachment size issue. This issue has already
                        // been written to the report. Just need to update the
                        // statistics info.
                        PostMigrationReport.WriteIssue(m_MySchemaMap.entity,
                                                       m_MySchemaMap.WIT,
                                                       Stats.MigrationStatus.Failed,
                                                       ReportIssueType.Info,
                                                       null, m_sourceId, IssueGroup.Wi,
                                                       null);
                    }
                    // set the bug migration status to done only if there were no
                    // problems with  initial view and any of the references
                    if ((!writeHistoryPassed || !refRecordStatus || !initialViewStatus) &&
                        m_cqParams.exitOnError)
                    {
                        // stop processing more records
                        CompactMe();
                        return(false);
                    }
                }
                catch (Exception ex)
                {
                    // creation of history failed
                    string errMsg = UtilityMethods.Format(CQResource.CQ_WI_MIG_FAILED, SourceId, ex.Message);
                    CQConverter.ReportWorkItemFailure(errMsg, SourceId, m_MySchemaMap.entity, m_MySchemaMap.WIT,
                                                      m_cqParams.exitOnError);
                    if (m_cqParams.exitOnError == true)
                    {
                        throw new ConverterException(errMsg);
                    }
                    else
                    {
                        // continue with another work item.. reporting this failure
                        CompactMe();
                        return(false);
                    }
                } // end of catch
                finally
                {
                }
            } // end of history items processing

            // add to pass count
            ConverterMain.MigrationReport.Statistics.NumberOfItems++;

            // add to per work item type section
            if (writeHistoryPassed)
            {
                PostMigrationReport.WriteIssue(m_MySchemaMap.entity, m_MySchemaMap.WIT,
                                               Stats.MigrationStatus.Passed,
                                               ReportIssueType.Info,
                                               null, m_sourceId, IssueGroup.Wi, null);
            }
            //compact current object
            CompactMe();
            return(true);
        } // end of Populate()
        /// <inheritdoc/>
        public TfsWorkItem GetWorkItemForIssue(string issueId, int issueActivityCount)
        {
            if (string.IsNullOrEmpty(issueId))
            {
                throw new ArgumentNullException(nameof(issueId));
            }

            if (this.parentWorkItemId == -1)
            {
                throw new Exception("Please run ConfigureAsync first.");
            }

            var hasChange = false;
            var parentWorkItem = this.workItems.Single(w => w.Id == this.parentWorkItemId);
            string[] commentParts = null;
            var workItemLink = parentWorkItem.Links.FirstOrDefault(l =>
                {
                    if (l.Comment.StartsWith(issueId))
                    {
                        commentParts = l.Comment.Split(':');
                        return true;
                    }

                    return false;
                });
            InMemoryWorkItem workItem = null;
            if (workItemLink != null)
            {
                if (!commentParts[1].Equals(issueActivityCount.ToString(CultureInfo.InvariantCulture)))
                {
                    hasChange = true;
                }

                workItem = this.workItems.Single(w => w.Id == workItemLink.RelatedWorkItemId);
            }
            else
            {
                workItem = new InMemoryWorkItem();
                hasChange = true;
            }

            var issueSignature = $"{issueId}:{issueActivityCount}";
            return new InMemoryTfsWorkItem(workItem) { HasChange = hasChange, IssueSignature = issueSignature };
        }
 public InMemoryTfsWorkItem(InMemoryWorkItem item)
     : base(item, typeof(InMemoryWorkItem))
 {
 }
        /// <summary>
        /// Creates a work item in memory.
        /// </summary>
        /// <param name="title">Work item title.</param>
        public int CreateWorkItem(string title)
        {
            var workItem = new InMemoryWorkItem { Title = title };
            this.workItems.Add(workItem);

            return workItem.Id;
        }
 public InMemoryTfsWorkItem(InMemoryWorkItem item)
     : base(item, typeof(InMemoryWorkItem))
 {
 }
Example #9
0
        /// <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);
        }
Example #10
0
        /// <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);
        }