Example #1
0
        /// <summary>
        /// The add work item for current project.
        /// </summary>
        /// <param name="projectName">
        /// The project name.
        /// </param>
        /// <param name="title">
        /// The title.
        /// </param>
        /// <param name="workItemTypeString">
        /// The work item type string.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>

        public static int AddWorkItemForCurrentProject(string projectName, string title, string workItemTypeString, string areapath = "", string linkend = "", int linkid = 0, string DocUrl = "")
        {
            WorkItemType workItemType =
                TfsManager.Instance.ItemsStore.Projects[projectName].WorkItemTypes[workItemTypeString];
            var wi = new WorkItem(workItemType)
            {
                Title = title
            };

            if (areapath != "" && areapath != projectName)
            {
                wi.AreaPath = areapath;
            }

            var requiredFields = GetRequiredFieldsForWorkItem(wi);

            var popup = new RequiredFields {
                DataContext = requiredFields
            };

            if (requiredFields.Count != 0)
            {
                //Thread.CurrentThread.CurrentCulture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
                //Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern = "dd.MM.yyyy";
                popup.Create(null, Icons.AddNewWorkItem);
                if (popup.IsCancelled && !popup.IsCreated)
                {
                    return(0);
                }
            }

            if (!SetRequiredFieldsForWorkIetm(requiredFields, wi))
            {
                return(0);
            }

            if (linkend != "" && linkid > 0)
            {
                if (TfsManager.Instance.ItemsStore.WorkItemLinkTypes.LinkTypeEnds.Contains(linkend))
                {
                    WorkItemLinkTypeEnd linkTypeEnd = TfsManager.Instance.ItemsStore.WorkItemLinkTypes.LinkTypeEnds[linkend];
                    wi.Links.Add(new RelatedLink(linkTypeEnd, linkid));
                }
            }

            if (DocUrl != "")
            {
                wi.Links.Add(new Hyperlink(DocUrl));
            }

            var _save_errors = wi.Validate();

            if (_save_errors.Count > 0)
            {
                return(0);
            }

            wi.Save();
            return(wi.Id);
        }
Example #2
0
        protected WorkItemLinkTypeEnd CalculateWorkItemLinkTypeEnd(WorkItemStore workItemStore)
        {
            WorkItemLinkTypeEnd linkTypeEnd = null;

            if (WorkItemRelationType == null)
            {
                return(null);
            }

            if (WorkItemRelationType is string)
            {
                string linkTypeEndName = WorkItemRelationType as string;

                WorkItemLinkTypeEndCollection linkTypeCollection = workItemStore.WorkItemLinkTypes.LinkTypeEnds;
                if (!linkTypeCollection.Contains(linkTypeEndName))
                {
                    throw new InvalidOperationException(string.Format("Work item link type \"{0}\" doesn't exist, cannot create links to connect to parent work item.", linkTypeEndName));
                }

                linkTypeEnd = workItemStore.WorkItemLinkTypes.LinkTypeEnds[linkTypeEndName];
            }
            else if (WorkItemRelationType is WorkItemLinkTypeEnd)
            {
                linkTypeEnd = WorkItemRelationType as WorkItemLinkTypeEnd;
            }
            else
            {
                throw new PSArgumentException("Work item link type only must be a string or WorkItemLinkTypeEnd object.");
            }

            return(linkTypeEnd);
        }
Example #3
0
        /// <summary>
        /// Adds a link to the work items with the given ids.
        /// </summary>
        /// <param name="ids">The ids.</param>
        /// <param name="linkTypeEnd">The link type.</param>
        /// <returns></returns>
        private bool AddLinks(int[] ids, WorkItemLinkTypeEnd linkTypeEnd)
        {
            // Check for OneToMany violations (e.g. more than one parent)
            if (ids.Length > 1 && linkTypeEnd.IsForwardLink == false && linkTypeEnd.LinkType.IsOneToMany)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.LinkError_OneToManyViolation, linkTypeEnd.Name));
            }

            // remove all links of this link type and only for ids which are going to add
            var tfsLinks = (from Link l in WorkItem.Links select l).ToArray();

            foreach (Link link in tfsLinks)
            {
                var workItemLink = link as RelatedLink;
                if (workItemLink != null)
                {
                    if (workItemLink.LinkTypeEnd.Id == linkTypeEnd.Id && ids.Contains(workItemLink.RelatedWorkItemId))
                    {
                        WorkItem.Links.Remove(link);
                    }
                }
            }

            // add new links for this type
            foreach (var id in ids)
            {
                var relatedLink = new RelatedLink(linkTypeEnd, id);
                WorkItem.Links.Add(relatedLink);
            }

            return(true);
        }
Example #4
0
        static void Main(string[] args)
        {
            int UserStoryID = 53;
            int TestCaseID  = 54;

            TfsTeamProjectCollection tfs;

            tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://ictfs2015:8080/tfs/DefaultCollection"));
            tfs.Authenticate();

            var      workItemStore = new WorkItemStore(tfs);
            WorkItem wit           = workItemStore.GetWorkItem(UserStoryID);

            //Set "Tested By" as the link type
            var linkTypes = workItemStore.WorkItemLinkTypes;
            WorkItemLinkType    testedBy    = linkTypes.FirstOrDefault(lt => lt.ForwardEnd.Name == "Tested By");
            WorkItemLinkTypeEnd linkTypeEnd = testedBy.ForwardEnd;

            //Add the link as related link.
            try
            {
                wit.Links.Add(new RelatedLink(linkTypeEnd, TestCaseID));
                wit.Save();
                Console.WriteLine(string.Format("Linked TestCase {0} to UserStory {1}", TestCaseID, UserStoryID));
            }
            catch (Exception ex)
            {
                // ignore "duplicate link" errors
                if (!ex.Message.StartsWith("TF26181"))
                {
                    Console.WriteLine("ex: " + ex.Message);
                }
            }
            Console.ReadLine();
        }
        protected override void ProcessRecordInEH()
        {
            WorkItemStore       workItemStore = EnsureWorkItemStore();
            WorkItemLinkTypeEnd linkTypeEnd   = EnsureWorkItemLinkTypeEnd(workItemStore);

            WorkItem[] workItems = QueryFromWorkItems(workItemStore).ToArray();
            if (workItems.Length == 0)
            {
                return;
            }

            WorkItem toWorkItem = workItemStore.GetWorkItem(RelatedWorkItemId);

            if (toWorkItem == null)
            {
                throw new ArgumentException(string.Format("Invalid to work item id: {0}.", RelatedWorkItemId));
            }

            foreach (var workItem in workItems)
            {
                workItem.Links.Add(new RelatedLink(linkTypeEnd, toWorkItem.Id));
                WriteObject(workItem);
            }

            workItemStore.BatchSave(workItems, SaveFlags.MergeLinks);
        }
Example #6
0
        private static void CreateTestRelation(WorkItemStore store, WorkItem workItem, int relationId)
        {
            WorkItemLinkTypeEnd hierarchyLinkType = store.WorkItemLinkTypes.LinkTypeEnds["Tests"];

            workItem.Links.Add(new WorkItemLink(hierarchyLinkType, relationId));
            //workItem.Save();
        }
Example #7
0
 private void CreateLinks(WorkItem workItem, IList <ILink> links)
 {
     workItem.Reset();
     foreach (Link link in links)
     {
         try
         {
             WorkItemLinkTypeEnd workItemLinkTypeEnd = m_workItemLinkTypeEndCollection[link.LinkTypeName];
             WorkItemLink        workItemLink        = new WorkItemLink(workItemLinkTypeEnd, link.EndWorkItemTfsId);
             workItem.WorkItemLinks.Add(workItemLink);
             workItem.Save();
             link.IsExistInTfs = true;
         }
         catch (ValidationException valEx)
         {
             link.Message = valEx.Message;
             workItem.Reset();
         }
         catch (TeamFoundationServerException tfsEx)
         {
             link.Message = tfsEx.Message;
             workItem.Reset();
         }
     }
 }
        private WorkItemLinkTypeEnd EnsureWorkItemLinkTypeEnd(WorkItemStore workItemStore)
        {
            WorkItemLinkTypeEnd linkTypeEnd = null;

            if (WorkItemRelationType == null)
            {
                throw new ArgumentException("Work item link type must be specified!");
            }
            else if (WorkItemRelationType is string)
            {
                string linkTypeEndName = WorkItemRelationType as string;

                WorkItemLinkTypeEndCollection linkTypeCollection = workItemStore.WorkItemLinkTypes.LinkTypeEnds;
                if (!linkTypeCollection.Contains(linkTypeEndName))
                {
                    throw new InvalidOperationException(string.Format("Work item link type \"{0}\" doesn't exist, cannot create links to connect to parent work item.", linkTypeEndName));
                }

                linkTypeEnd = workItemStore.WorkItemLinkTypes.LinkTypeEnds[linkTypeEndName];
            }
            else if (WorkItemRelationType is WorkItemLinkTypeEnd)
            {
                linkTypeEnd = WorkItemRelationType as WorkItemLinkTypeEnd;
            }

            return(linkTypeEnd);
        }
        private WorkItemLinkTypeEnd ParseLinkEnd(WiLink link, WorkItem wi)
        {
            var props    = link.WiType?.Split('-');
            var linkType = wi.Project.Store.WorkItemLinkTypes.SingleOrDefault(lt => lt.ReferenceName == props?[0]);

            if (linkType == null)
            {
                Logger.Log(LogLevel.Error, $"'{link.ToString()}' - link type ({props?[0]}) does not exist in project");
                return(null);
            }

            WorkItemLinkTypeEnd linkEnd = null;

            if (linkType.IsDirectional)
            {
                if (props?.Length > 1)
                {
                    linkEnd = props[1] == "Forward" ? linkType.ForwardEnd : linkType.ReverseEnd;
                }
                else
                {
                    Logger.Log(LogLevel.Error, $"'{link.ToString()}' - link direction not provided for '{wi.Id}'.");
                }
            }
            else
            {
                linkEnd = linkType.ForwardEnd;
            }

            return(linkEnd);
        }
Example #10
0
 public void SaveLinkedItem(WorkItem parent, WorkItem item, WorkItemLinkTypeEnd linkType)
 {
     item.Save();
     // Add link to parent item and save it
     parent.Links.Add(new RelatedLink(linkType, item.Id));
     parent.Save();
 }
        public void Sprint1Plan()
        {
            TfsTeamProjectCollection tpc = TfsConnect();

            // Load tasks from config file

            XmlDocument xmlInput = new XmlDocument();

            xmlInput.Load(InputFile);
            XmlNodeList tasks = xmlInput.SelectNodes("//plan/task");

            // Get PBI work items

            WorkItemStore      store      = new WorkItemStore(tpc);
            Project            project    = store.Projects[TeamProject];
            string             wiql       = "SELECT [System.Id] FROM WorkItems " + "WHERE [System.TeamProject] = '" + TeamProject + "' AND [System.WorkItemType] ='Product Backlog Item'";
            WorkItemCollection collection = store.Query(wiql);

            // Loop through each PBI

            int count = 0;

            for (int i = 0; i < collection.Count; i++)
            {
                WorkItem PBI = collection[i];

                // Loop through each Task

                foreach (XmlNode task in tasks)
                {
                    WorkItem wi = new WorkItem(project.WorkItemTypes["task"]);
                    wi.Title         = task["title"].InnerText;
                    wi.IterationPath = @"Fabrikam\Release 1\Sprint 1";
                    wi.Fields["Microsoft.VSTS.Scheduling.RemainingWork"].Value = Convert.ToInt32(task["remainingwork"].InnerText);

                    ArrayList ValidationResult = wi.Validate();
                    if (ValidationResult.Count > 0)
                    {
                        Microsoft.TeamFoundation.WorkItemTracking.Client.Field badField = (Microsoft.TeamFoundation.WorkItemTracking.Client.Field)ValidationResult[0];
                        Console.WriteLine();
                        Console.WriteLine("  Invalid \"{0}\" value \"{1}\" ({2})", badField.Name, badField.Value, badField.Status);
                        return;
                    }
                    Console.Write(".");
                    wi.Save();

                    // Save link to parent PBI

                    WorkItemLinkTypeEnd childLink = store.WorkItemLinkTypes.LinkTypeEnds["Parent"];
                    wi.WorkItemLinks.Add(new WorkItemLink(childLink, PBI.Id));
                    wi.Save();
                    count++;
                }
            }

            // Done

            Console.WriteLine(string.Format(" ({0} tasks added)", count));
        }
Example #12
0
 public void WorkItemLinkAlreadyExists(int sourceId, WorkItemLinkTypeEnd destLinkType, int destId)
 {
     this.logger.Log(
         LogLevel.Warning,
         "Work item link '{1}' from #{0} to #{2} already exists",
         sourceId,
         destLinkType,
         destId);
 }
 public void AddingWorkItemLink(int sourceId, WorkItemLinkTypeEnd destLinkType, int destId)
 {
     this.logger.Log(
         LogLevel.Information,
         "Adding work item link '{1}' from #{0} to #{2}",
         sourceId,
         destLinkType,
         destId);
 }
Example #14
0
 public void AddingWorkItemLink(int sourceId, WorkItemLinkTypeEnd destLinkType, int destId)
 {
     this.logger.Log(
         LogLevel.Information,
         "Adding work item link '{1}' from #{0} to #{2}",
         sourceId,
         destLinkType,
         destId);
 }
Example #15
0
        private static void CreateTestedByLink(SharedStepsObject sharedStepsObject, int parentId)
        {
            WorkItemStore       workItemStore = sharedStepsObject.project.Store;
            Project             teamProject   = workItemStore.Projects["Schwans Company"];
            var                 linkTypes     = workItemStore.WorkItemLinkTypes;
            WorkItemLinkType    testedBy      = linkTypes.FirstOrDefault(lt => lt.ForwardEnd.Name == "Tested By");
            WorkItemLinkTypeEnd linkTypeEnd   = testedBy.ForwardEnd;

            sharedStepsObject.testedWorkItem.Links.Add(new RelatedLink(linkTypeEnd, sharedStepsObject.id + 1));
            var result = CheckValidationResult(sharedStepsObject.testedWorkItem);
        }
Example #16
0
        internal static WorkItemLinkTypeEndWrapper GetInstance()
        {
            WorkItemLinkTypeEnd real = default(WorkItemLinkTypeEnd);

            RealInstanceFactory(ref real);
            var instance = (WorkItemLinkTypeEndWrapper)WorkItemLinkTypeEndWrapper.GetWrapper(real);

            InstanceFactory(ref instance);
            if (instance == null)
            {
                Assert.Inconclusive("Could not Create Test Instance");
            }
            return(instance);
        }
Example #17
0
        /// <summary>
        /// Link Work Items in TFS
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="targetWorkItemId">
        /// The target Work Item Id.
        /// </param>
        /// <param name="linkTypeEndName">
        /// The link Type End Name.
        /// </param>
        /// <param name="comments">
        /// The comments.
        /// </param>
        public void LinkWorkItems(WorkItem source, int targetWorkItemId, string linkTypeEndName, string comments)
        {
            WorkItem wItem = tfsManager.GetWorkItem(targetWorkItemId);

            if (wItem != null)
            {
                WorkItemLinkTypeEnd linkTypeEnd = tfsManager.GetAllWorkItemLinksTypes().LinkTypeEnds[linkTypeEndName];
                var link = new RelatedLink(linkTypeEnd, targetWorkItemId)
                {
                    Comment = comments
                };
                source.Links.Add(link);
                source.Save();
            }
        }
Example #18
0
        private void AddWorkItemRelationLinkToWorkItemsIfNeeded(WorkItemStore workItemStore, WorkItem[] workItems)
        {
            WorkItemLinkTypeEnd linkTypeEnd     = CalculateWorkItemLinkTypeEnd(workItemStore);
            WorkItem            relatedWorkItem = workItemStore.GetWorkItem(RelatedWorkItemId);

            if (relatedWorkItem == null)
            {
                throw new PSArgumentException(string.Format("Invalid to work item id: {0}.", RelatedWorkItemId));
            }

            foreach (var workItem in workItems)
            {
                workItem.Links.Add(new RelatedLink(linkTypeEnd, relatedWorkItem.Id));
            }
        }
Example #19
0
 public void Link(int parent, int child, String linkType)
 {
     try
     {
         Console.WriteLine(String.Format("正在关联{0}--{1}", parent, child));
         WorkItemLinkTypeEnd linkTypeEnd = ItemStore.WorkItemLinkTypes.LinkTypeEnds[linkType];
         Item = ItemStore.GetWorkItem(parent);
         Item.Links.Add(new RelatedLink(linkTypeEnd, child));
         Item.Save();
     }
     catch
     {
         Console.WriteLine(String.Format("{0}--{1}关联已存在", parent, child));
     }
 }
        private void Autoassign(WorkItemStore workItemStore, WorkItem workItem)
        {
            workItem.Fields[DefectField.AreaPath.FieldName()].Value   = Config.UserAreaPath;
            workItem.Fields[DefectField.AssignedTo.FieldName()].Value = workItemStore.UserIdentityName;

            string path = GetCurrentIterationPath(workItemStore);

            workItem.Fields[DefectField.IterationPath.FieldName()].Value = path;

            if (!workItem.Links.Exist(int.Parse(Config.WorkingFeature)))
            {
                // Docs Link to w.i. as parent of...
                // https://docs.microsoft.com/en-us/vsts/work/customize/reference/link-type-element-reference
                WorkItemLinkTypeEnd linkType = workItemStore.WorkItemLinkTypes.LinkTypeEnds[DefectLinkType.Child.FieldName()];
                workItem.Links.Add(new RelatedLink(linkType, int.Parse(Config.WorkingFeature)));
            }
        }
Example #21
0
        private string CalculateWorkItemLinkTypeEndName()
        {
            if (WorkItemRelationType == null)
            {
                return(null);
            }

            if (WorkItemRelationType is string)
            {
                return(WorkItemRelationType as string);
            }
            else if (WorkItemRelationType is WorkItemLinkTypeEnd)
            {
                WorkItemLinkTypeEnd linkTypeEnd = WorkItemRelationType as WorkItemLinkTypeEnd;
                return(linkTypeEnd.Name);
            }

            throw new PSArgumentException("WorkItemRelationType must be either a string or a WorkItemLinkTypeEnd object.");
        }
Example #22
0
        public WorkItem CreateNewLinkedWorkItem(WorkItem parent,
                                                WorkItemLinkTypeEnd linkType,
                                                WorkItemType workItemType,
                                                string title,
                                                string comment)
        {
            WorkItemType wit = TeamProject.WorkItemTypes[workItemType.Name];

            // Create the work item.
            WorkItem workItem = new WorkItem(wit);

            workItem.Title         = title;
            workItem.Description   = comment;
            workItem.AreaPath      = parent.AreaPath;
            workItem.IterationPath = parent.IterationPath;

            // Return the newly created work item
            return(workItem);
        }
Example #23
0
        public bool IsVisibleNewLinkedWorkItem(WorkItem item, WorkItemLinkTypeEnd selectedLinkTypeEnd)
        {
            bool isStateVisible = false;

            foreach (ICustomState customState in ConfigurationViewModel.CustomStates)
            {
                if (customState.WorkItemStates.Contains(item.State))
                {
                    isStateVisible = true;
                    break;
                }
            }
            bool isLinkTypeEndVisible = ConfigurationViewModel.CurrentLinkType == null ||
                                        ConfigurationViewModel.CurrentLinkType.ForwardEnd == selectedLinkTypeEnd ||
                                        ConfigurationViewModel.CurrentLinkType.ReverseEnd == selectedLinkTypeEnd;

            if (isLinkTypeEndVisible && isStateVisible && ConfigurationViewModel.ChildItems.Contains(item.Type.Name))
            {
                TaskboardService.ApplyConfigurationToLink(item, SelectedWorkItem);
                return(true);
            }
            return(false);
        }
Example #24
0
        private void CreateRelatedLink(WorkItemData wiSourceL, RelatedLink item, WorkItemData wiTargetL)
        {
            RelatedLink  rl        = (RelatedLink)item;
            WorkItemData wiSourceR = null;
            WorkItemData wiTargetR = null;

            try
            {
                wiSourceR = Engine.Source.WorkItems.GetWorkItem(rl.RelatedWorkItemId.ToString());
            }
            catch (Exception ex)
            {
                Log.LogError(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);
            }
            catch (Exception ex)
            {
                Log.LogError(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.ToWorkItem().Links
                        where l is RelatedLink &&
                        ((RelatedLink)l).RelatedWorkItemId.ToString() == wiTargetR.Id &&
                        ((RelatedLink)l).LinkTypeEnd.ImmutableName == item.LinkTypeEnd.ImmutableName
                        select(RelatedLink) l).SingleOrDefault();
                    IsExisting = (exist != null);
                }
                catch (Exception ex)
                {
                    Log.LogError(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.ToWorkItem().IsAccessDenied)
                {
                    if (wiSourceR.Id != wiTargetR.Id)
                    {
                        Log.LogInformation("  [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);
                        var client = (TfsWorkItemMigrationClient)Engine.Target.WorkItems;
                        if (!client.Store.WorkItemLinkTypes.LinkTypeEnds.Contains(rl.LinkTypeEnd.ImmutableName))
                        {
                            Log.LogError($"  [SKIP] Unable to migrate Link because type {rl.LinkTypeEnd.ImmutableName} does not exist in the target project.");
                            return;
                        }

                        WorkItemLinkTypeEnd linkTypeEnd = client.Store.WorkItemLinkTypes.LinkTypeEnds[rl.LinkTypeEnd.ImmutableName];
                        RelatedLink         newRl       = new RelatedLink(linkTypeEnd, int.Parse(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.ToWorkItem().Links
                                where l is RelatedLink &&
                                ((RelatedLink)l).LinkTypeEnd.ImmutableName == "System.LinkTypes.Hierarchy-Reverse"
                                select(RelatedLink) l).SingleOrDefault();
                            if (potentialParentConflictLink != null)
                            {
                                wiTargetR.ToWorkItem().Links.Remove(potentialParentConflictLink);
                            }
                            linkTypeEnd = ((TfsWorkItemMigrationClient)Engine.Target.WorkItems).Store.WorkItemLinkTypes.LinkTypeEnds["System.LinkTypes.Hierarchy-Reverse"];
                            RelatedLink newLl = new RelatedLink(linkTypeEnd, int.Parse(wiTargetL.Id));
                            wiTargetR.ToWorkItem().Links.Add(newLl);
                            wiTargetR.ToWorkItem().Fields["System.ChangedBy"].Value = "Migration";
                            wiTargetR.SaveToAzureDevOps();
                        }
                        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.ToWorkItem().Links
                                    where l is RelatedLink &&
                                    ((RelatedLink)l).LinkTypeEnd.ImmutableName == "System.LinkTypes.Hierarchy-Reverse"
                                    select(RelatedLink) l).SingleOrDefault();
                                if (potentialParentConflictLink != null)
                                {
                                    wiTargetL.ToWorkItem().Links.Remove(potentialParentConflictLink);
                                }
                            }
                            wiTargetL.ToWorkItem().Links.Add(newRl);
                            if (_save)
                            {
                                wiTargetL.ToWorkItem().Fields["System.ChangedBy"].Value = "Migration";
                                wiTargetL.SaveToAzureDevOps();
                            }
                        }
                        Log.LogInformation(
                            "  [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.LogInformation(
                            "  [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.LogInformation("  [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.ToWorkItem().IsAccessDenied)
                    {
                        Log.LogInformation("  [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.LogInformation("  [SKIP] Cant find wiTargetR where wiSourceL={0}, wiSourceR={1}, wiTargetL={2}", wiSourceL.Id, wiSourceR.Id, wiTargetL.Id);
            }
        }
 public void WorkItemLinkAlreadyExists(int sourceId, WorkItemLinkTypeEnd destLinkType, int destId)
 {
     this.logger.Log(
         LogLevel.Warning,
         "Work item link '{1}' from #{0} to #{2} already exists",
         sourceId,
         destLinkType,
         destId);
 }
Example #26
0
        /// <summary>
        /// Creates the work items.
        /// </summary>
        /// <param name="baseWorkItemIds">The base work item ids.</param>
        /// <param name="selectedPlanningTemplate">The selected planning template.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentException">
        /// Invalid WorkItemType
        /// or
        /// or
        /// Invalid WorkItemLinkType
        /// </exception>
        public WorkItem[] CreateRelatedWorkItems(int[] baseWorkItemIds, PlanningTemplate selectedPlanningTemplate)
        {
            TfsTeamProjectCollection projectCollection = this.GetTeamProjectCollection();
            WorkItemStore            store             = projectCollection.GetService <WorkItemStore>();

            Dictionary <WorkItemField, String> workItemFieldMatches = new Dictionary <WorkItemField, string>(ConfigurationManager.CurrentConfiguration.WorkItemFieldMatches.Count);

            // Load default fields from configuration
            foreach (WorkItemFieldMatch workItemFieldMatch in ConfigurationManager.CurrentConfiguration.WorkItemFieldMatches)
            {
                workItemFieldMatches.Add(workItemFieldMatch.Field, workItemFieldMatch.Value);
            }


            List <WorkItem> workItemsToSave = new List <WorkItem>();

            foreach (int workItemId in baseWorkItemIds)
            {
                WorkItem baseWorkItem = store.GetWorkItem(workItemId);
                Project  project      = baseWorkItem.Project;

                foreach (TaskTemplate taskTemplate in selectedPlanningTemplate.TasksToCreateCollection)
                {
                    // If Task Quantity is zero, ignore it
                    if (taskTemplate.Quantity <= 0)
                    {
                        continue;
                    }

                    #region Get Work Item Type

                    // Check if the Work Item Type exists
                    if (!project.WorkItemTypes.Contains(taskTemplate.WorkItemType))
                    {
                        throw new ArgumentException("Invalid WorkItemType");
                    }

                    WorkItemType wiType = project.WorkItemTypes[taskTemplate.WorkItemType];

                    #endregion

                    // Predefined fields match
                    foreach (KeyValuePair <WorkItemField, String> fields in workItemFieldMatches)
                    {
                        if (!wiType.FieldDefinitions.Contains(workItemFieldMatches[WorkItemField.AssignedTo]))
                        {
                            throw new ArgumentException(String.Format("WorkItem {0} doesn't contain field with name {1}", taskTemplate.WorkItemType, workItemFieldMatches[WorkItemField.AssignedTo]));
                        }
                    }

                    // Get the relation link type
                    if (!store.WorkItemLinkTypes.Contains(taskTemplate.WorkItemLinkType))
                    {
                        throw new ArgumentException("Invalid WorkItemLinkType");
                    }

                    WorkItemLinkTypeEnd relationLinkType = store.WorkItemLinkTypes[taskTemplate.WorkItemLinkType].ReverseEnd;

                    foreach (TaskTemplateInstance taskTemplateInstance in taskTemplate.InstancesCollection)
                    {
                        WorkItem newWorkItem = wiType.NewWorkItem();

                        newWorkItem.AreaId        = baseWorkItem.AreaId;
                        newWorkItem.AreaPath      = baseWorkItem.AreaPath;
                        newWorkItem.IterationPath = baseWorkItem.IterationPath;

                        // Copy Tags
                        if (!String.IsNullOrWhiteSpace(baseWorkItem.Tags))
                        {
                            newWorkItem["Tags"] = baseWorkItem.Tags;
                        }

                        newWorkItem.Title = String.Format("{0}{1}{2}", taskTemplate.Prefix, baseWorkItem.Title, taskTemplate.Sufix);

                        // AssignedTo
                        newWorkItem.UpdateField(workItemFieldMatches[WorkItemField.AssignedTo], taskTemplateInstance.AssignedTo);

                        // Original Estimate
                        newWorkItem.UpdateField(workItemFieldMatches[WorkItemField.OriginalEstimate], taskTemplateInstance.EstimatedTime);

                        // Remaining Work
                        newWorkItem.UpdateField(workItemFieldMatches[WorkItemField.RemainingWork], taskTemplateInstance.EstimatedTime);

                        // Custom Properties
                        if (taskTemplate.CustomProperties != null && taskTemplate.CustomProperties.Count > 0)
                        {
                            foreach (TaskTemplateCustomProperty customProperty in taskTemplate.CustomProperties)
                            {
                                newWorkItem.UpdateField(customProperty.Name, customProperty.Value);
                            }
                        }

                        if (taskTemplate.IsCopyDescriptionEnabled)
                        {
                            newWorkItem.Description = baseWorkItem.Description;

                            if (String.IsNullOrWhiteSpace(newWorkItem.Description))
                            {
                                // Maybe this is a bug
                                if (baseWorkItem.Fields.Contains("Repro Steps"))
                                {
                                    newWorkItem.Description = baseWorkItem.Fields["Repro Steps"].Value.ToString();
                                }
                            }
                        }

                        newWorkItem.Links.Add(new RelatedLink(relationLinkType, baseWorkItem.Id));

                        workItemsToSave.Add(newWorkItem);
                    }
                }
            }

            var witems = workItemsToSave.ToArray();

            store.BatchSave(witems);

            return(witems);
        }
Example #27
0
        /* Set links between workitems */
        private void CreateLinks(List <WorkItem> workItemCollection, WorkItemStore sourceStore)
        {
            List <int>         linkedWorkItemList       = new List <int>();
            WorkItemCollection targetWorkItemCollection = GetWorkItemCollection();

            foreach (WorkItem workItem in workItemCollection)
            {
                WorkItemLinkCollection links = workItem.WorkItemLinks;
                if (links.Count > 0)
                {
                    int      newWorkItemID = (int)itemMap[workItem.Id];
                    WorkItem newWorkItem   = store.GetWorkItem(newWorkItemID);

                    foreach (WorkItemLink link in links)
                    {
                        try
                        {
                            WorkItem targetItem = sourceStore.GetWorkItem(link.TargetId);
                            if (itemMap.ContainsKey(link.TargetId) && targetItem != null)
                            {
                                int targetWorkItemID = 0;
                                if (itemMap.ContainsKey(link.TargetId))
                                {
                                    targetWorkItemID = (int)itemMap[link.TargetId];
                                }

                                //if the link is not already created(check if target id is not in list)
                                if (!linkedWorkItemList.Contains(link.TargetId))
                                {
                                    try
                                    {
                                        WorkItemLinkTypeEnd linkTypeEnd = store.WorkItemLinkTypes.LinkTypeEnds[link.LinkTypeEnd.Name];
                                        newWorkItem.Links.Add(new RelatedLink(linkTypeEnd, targetWorkItemID));

                                        ArrayList array = newWorkItem.Validate();
                                        if (array.Count == 0)
                                        {
                                            newWorkItem.Save();
                                        }
                                        else
                                        {
                                            logger.Info("WorkItem Validation failed at link setup for work item: " + workItem.Id);
                                        }
                                    }
                                    catch (Exception)
                                    {
                                        logger.Info(String.Format("Error occured when crearting link for work item: {0} target item: {1}", workItem.Id, link.TargetId));
                                    }
                                }
                            }
                            else
                            {
                                logger.Info("Link is not created for work item: " + workItem.Id + " - target item: " + link.TargetId + " does not exist");
                            }
                        }
                        catch (Exception)
                        {
                            logger.Info("Link is not created for work item: " + workItem.Id + " - target item: " + link.TargetId + " is not in Source TFS or you do not have permission to access");
                        }
                    }
                    //add the work item to list if the links are processed
                    linkedWorkItemList.Add(workItem.Id);
                }
            }
        }
        static partial void RealInstanceFactory(ref WorkItemLinkTypeEnd real, string callerName)
        {
            var linkType = WorkItemLinkTypeWrapper_UnitTests.GetRealInstance();

            real = linkType.ForwardEnd;
        }
Example #29
0
        public static int ChangeLinkTypes(int[] qdata, WorkItemLinkType fromlink, WorkItemLinkType tolink)
        {
            int changedlinks = 0;

            foreach (int itm in qdata)
            {
                if (itm == 0)
                {
                    continue;
                }

                WorkItem wi = Utilities.wistore.GetWorkItem(itm);
                foreach (var link in wi.Links.OfType <RelatedLink>().Where(x => x.LinkTypeEnd.LinkType.ReferenceName == fromlink.ReferenceName).ToList())
                {
                    WorkItemLinkTypeEnd linkTypeEnd = Utilities.wistore.WorkItemLinkTypes.LinkTypeEnds[(link.LinkTypeEnd.IsForwardLink ? tolink.ForwardEnd.Name : tolink.ReverseEnd.Name)];
                    Utilities.OutputCommandString(string.Format("Updated WorkItemID={0}, OriginalLink={1}, NewLink={2}", wi.Id, link.LinkTypeEnd.Name, linkTypeEnd.Name));

                    if (wi.IsDirty)
                    {
                        try
                        {
                            wi.Save();
                        }
                        catch (Exception ex)
                        {
                            var result = MessageBox.Show(ex.Message, "Failed to save dirty Work Item #" + wi.Id, MessageBoxButtons.AbortRetryIgnore);
                            Utilities.OutputCommandString(ex.ToString());
                            if (result == DialogResult.Abort)
                            {
                                return(changedlinks);
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }
                    try
                    {
                        wi.Links.Add(new RelatedLink(linkTypeEnd, link.RelatedWorkItemId));
                        wi.Save();
                        changedlinks++;
                    }
                    catch (Exception ex)
                    {
                        var result = MessageBox.Show(ex.Message, "Failed to add new link to Work Item #" + wi.Id, MessageBoxButtons.AbortRetryIgnore);
                        Utilities.OutputCommandString(ex.ToString());
                        if (result == DialogResult.Abort)
                        {
                            return(changedlinks);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    try
                    {
                        wi.Links.Remove(link);
                        wi.Save();
                    }
                    catch (Exception ex)
                    {
                        var result = MessageBox.Show(ex.Message, "Failed to remove original link from Work Item #" + wi.Id, MessageBoxButtons.AbortRetryIgnore);
                        Utilities.OutputCommandString(ex.ToString());
                        if (result == DialogResult.Abort)
                        {
                            return(changedlinks);
                        }
                        else
                        {
                            continue;
                        }
                    }
                }
            }

            return(changedlinks);
        }
Example #30
0
        private void CreateRelatedLink(WorkItem wiSourceL, RelatedLink item, WorkItem wiTargetL, WorkItemStoreContext sourceStore, WorkItemStoreContext targetStore)
        {
            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);
                        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 CreatePBIs()
        {
            TfsTeamProjectCollection tpc = TfsConnect();

            int       count     = 0;
            Hashtable workItems = new Hashtable();

            // Validate that it's the right kind of team project

            WorkItemStore store   = new WorkItemStore(tpc);
            Project       project = store.Projects[TeamProject];

            if (!project.WorkItemTypes.Contains("Product Backlog Item"))
            {
                Console.WriteLine("This team project was not created using the Visual Studio Scrum process template.");
                return;
            }

            // Load work items

            XmlDocument xmlInput = new XmlDocument();

            xmlInput.Load(InputFile);
            XmlNodeList items = xmlInput.SelectNodes("//backlog/item");

            foreach (XmlNode item in items)
            {
                Console.Write(".");
                string WIT   = item["type"].InnerText.Trim().ToLower();
                string title = item["title"].InnerText;
                string state;
                if (item["state"] == null)
                {
                    state = "approved";
                }
                else
                {
                    state = item["state"].InnerText.ToLower();
                }
                WorkItem wi = new WorkItem(project.WorkItemTypes[WIT]);
                wi.Title = title;
                if (item["description"] != null)
                {
                    wi.Description = item["description"].InnerText;
                }
                else
                {
                    wi.Description = title;
                }
                if (item["reprosteps"] != null)
                {
                    wi.Fields["Microsoft.VSTS.TCM.ReproSteps"].Value = item["reprosteps"].InnerText;
                }
                if (item["acceptancecriteria"] != null)
                {
                    wi.Fields["Microsoft.VSTS.Common.AcceptanceCriteria"].Value = item["acceptancecriteria"].InnerText;
                }
                wi.AreaPath = TeamProject + item["area"].InnerText;
                if (item["iteration"] != null)
                {
                    wi.IterationPath = TeamProject + item["iteration"].InnerText;
                }
                wi.Fields["System.AssignedTo"].Value = ProductOwner;
                if (state == "approved" || state == "active")
                {
                    if (item["businessvalue"] != null && item["businessvalue"].InnerText != "")
                    {
                        wi.Fields["Microsoft.VSTS.Common.BusinessValue"].Value = item["businessvalue"].InnerText;
                    }
                    if (item["effort"] != null && item["effort"].InnerText != "")
                    {
                        wi.Fields["Microsoft.VSTS.Scheduling.Effort"].Value = item["effort"].InnerText;
                    }
                    if (item["order"] != null && item["order"].InnerText != "")
                    {
                        wi.Fields["Microsoft.VSTS.Common.BacklogPriority"].Value = item["order"].InnerText;
                    }
                }

                ArrayList ValidationResult = wi.Validate();
                if (ValidationResult.Count > 0)
                {
                    Microsoft.TeamFoundation.WorkItemTracking.Client.Field badField = (Microsoft.TeamFoundation.WorkItemTracking.Client.Field)ValidationResult[0];
                    Console.WriteLine();
                    Console.WriteLine("  Invalid \"{0}\" value \"{1}\" ({2})", badField.Name, badField.Value, badField.Status);
                    return;
                }
                wi.Save();
                count++;
                workItems.Add(wi.Id, wi.Title.Trim().ToLower());

                // linked items?

                if (item["parent"] != null)
                {
                    string parent   = item["parent"].InnerText.Trim().ToLower();
                    int    parentId = 0;
                    foreach (DictionaryEntry candidate in workItems)
                    {
                        if (candidate.Value.ToString() == parent)
                        {
                            parentId = Convert.ToInt32(candidate.Key);
                        }
                    }
                    if (parentId > 0)
                    {
                        // lookup child link type

                        WorkItemLinkTypeEnd childLink = store.WorkItemLinkTypes.LinkTypeEnds["Parent"];
                        wi.WorkItemLinks.Add(new WorkItemLink(childLink, parentId));
                        wi.Save();
                    }
                }

                if (state == "approved")
                {
                    wi.State = "Approved";
                    wi.Save();
                }
                else if (state == "active")
                {
                    wi.State = "Active";
                    wi.Save();
                }
                else if (state == "committed")
                {
                    wi.State = "Committed";
                    wi.Save();
                }
                else if (state == "done")
                {
                    wi.State = "Done";
                    wi.Save();
                }
            }

            // Done

            Console.WriteLine(string.Format(" ({0} PBIs created)", count));
        }
        public void CreateSprint1TestPlan()
        {
            TfsTeamProjectCollection   tpc     = TfsConnect();
            ITestManagementTeamProject project = tpc.GetService <ITestManagementService>().GetTeamProject(TeamProject);

            // Create test plan if none exist
            //
            // See http://bit.ly/2dup2XY for why we can't delete Test Plans or Suites at this point in time
            //
            // If this routine isn't creating the test plan and/or test suites for you, you'll need to manually
            // delete the Test Plan and Test Suites using witadmin

            WorkItemStore      store     = new WorkItemStore(tpc);
            string             wiql      = "SELECT [System.Id] FROM WorkItems " + "WHERE [System.TeamProject] = '" + TeamProject + "' AND [System.WorkItemType] ='Test Plan' AND [System.Title] = 'Sprint 1'";
            WorkItemCollection workItems = store.Query(wiql);
            int testPlanCount            = workItems.Count;

            wiql = "SELECT [System.Id] FROM WorkItems " + "WHERE [System.TeamProject] = '" + TeamProject + "' AND [System.WorkItemType] ='Test Suite'";
            int       testSuiteCount = store.Query(wiql).Count;
            ITestPlan testPlan;

            if (testPlanCount == 0)
            {
                testPlan           = project.TestPlans.Create();
                testPlan.Name      = "Sprint 1";
                testPlan.Iteration = @"Fabrikam\Release 1\Sprint 1";
                testPlan.Save();
                Console.WriteLine(" . (1 plan created)");
            }
            else
            {
                testPlan = project.TestPlans.Find(workItems[0].Id);
                Console.WriteLine(" . (plan exists)");
            }

            // Create Test Suites if non exist

            if (testSuiteCount <= 10) // May create duplicate test suites
            {
                Console.Write(" Creating sprint 1 test suites ");

                // suites

                int count = 0;
                IStaticTestSuite staticSuite = project.TestSuites.CreateStatic();
                staticSuite.Title = "Automated";
                testPlan.RootSuite.Entries.Add(staticSuite);
                testPlan.Save();
                Console.Write(".");
                count++;

                staticSuite       = project.TestSuites.CreateStatic();
                staticSuite.Title = "Regression";
                testPlan.RootSuite.Entries.Add(staticSuite);
                testPlan.Save();
                Console.Write(".");
                count++;

                // Requirement-based suites

                // Get PBI work items

                wiql      = "SELECT [System.Id] FROM WorkItems " + "WHERE [System.TeamProject] = '" + TeamProject + "' AND [System.WorkItemType] ='Product Backlog Item'";
                workItems = store.Query(wiql);
                for (int i = 0; i < workItems.Count; i++)
                {
                    WorkItem pbi = workItems[i];

                    // Link Test Case to PBI

                    int testCaseID = (int)TestCases[pbi.Title.ToLower()];
                    WorkItemLinkTypeEnd testedByLink = store.WorkItemLinkTypes.LinkTypeEnds["Tested By"];
                    pbi.WorkItemLinks.Add(new WorkItemLink(testedByLink, testCaseID));
                    pbi.Save();

                    // Create Requirement-based test suite

                    IRequirementTestSuite reqSuite = project.TestSuites.CreateRequirement(pbi);
                    reqSuite.Title = pbi.Title;
                    testPlan.RootSuite.Entries.Add(reqSuite);
                    testPlan.Save();
                    Console.Write(".");
                    count++;
                }

                // Query-based suites

                IDynamicTestSuite querySuite = project.TestSuites.CreateDynamic();
                querySuite.Title = "UI Tests";
                querySuite.Query = project.CreateTestQuery(@"SELECT [System.Id],[System.WorkItemType],[System.Title],[Microsoft.VSTS.Common.Priority],[System.AssignedTo],[System.AreaPath] FROM WorkItems WHERE [System.TeamProject] = @project AND [System.WorkItemType] IN GROUP 'Microsoft.TestCaseCategory' AND [System.AreaPath] UNDER 'Fabrikam' AND [System.IterationPath] UNDER 'Fabrikam\Release 1\Sprint 1' AND [System.Title] CONTAINS 'ui'");
                testPlan.RootSuite.Entries.Add(querySuite);
                testPlan.Save();
                Console.Write(".");
                count++;

                querySuite       = project.TestSuites.CreateDynamic();
                querySuite.Title = "Bug Existence Tests";
                querySuite.Query = project.CreateTestQuery(@"SELECT [System.Id],[System.WorkItemType],[System.Title],[Microsoft.VSTS.Common.Priority],[System.AssignedTo],[System.AreaPath] FROM WorkItems WHERE [System.TeamProject] = @project AND [System.WorkItemType] IN GROUP 'Microsoft.TestCaseCategory' AND [System.AreaPath] UNDER 'Fabrikam' AND [System.IterationPath] UNDER 'Fabrikam\Release 1\Sprint 1' AND [System.Title] CONTAINS 'bug'");
                testPlan.RootSuite.Entries.Add(querySuite);
                testPlan.Save();
                Console.Write(".");
                count++;

                Console.WriteLine(string.Format(" ({0} suites created)", count));
            }
        }