/// <summary> /// Gets the stub associated with the work item if it exists, otherwise a new one is /// created, added to the collection and returned /// </summary> /// <param name="wi">The Work Item to check</param> /// <returns>The associated WorkItemStub</returns> private WorkItemStub CheckStub(WorkItem wi) { //Perform a find on the ID, if it is found, s is populated WorkItemStub s = GetStub((int)wi.Fields[CoreField.Id].Value); //If it isn't found, create a new work item stub if (s == null) { s = new WorkItemStub(); s.ID = (int)wi.Fields[CoreField.Id].Value; s.Title = wi.Fields[CoreField.Title].Value.ToString(); s.WorkItemTypeName = wi.Fields[CoreField.WorkItemType].Value.ToString(); s.Iteration = wi.Fields[CoreField.IterationPath].Value.ToString(); if (!_allNodeTypes.Contains(s.WorkItemTypeName)) { _allNodeTypes.Add(s.WorkItemTypeName); } //Check to see if the iteration exists in the list of iterations and add it if it doesn't if (!_iterations.Contains(s.Iteration)) { _iterations.Add(s.Iteration); } _workItemStubs.Add(s); } return(s); }
/// <summary> /// Checks to see if the work item stub exists /// </summary> /// <param name="id">The ID of the work item to find</param> /// <returns>The work item stub or null if it isn't found</returns> private WorkItemStub GetStub(int id) { //Perform a find on the ID, if it is found, s is populated WorkItemStub s = _workItemStubs.Find( delegate(WorkItemStub stub) { return(stub.ID == id); } ); return(s); }
/// <summary> /// The work item to process /// </summary> /// <param name="wi"></param> private void ProcessWorkItemCS(WorkItem wi) { //Get a reference to or add the wi to the workitemstub list WorkItemStub s = CheckStub(wi); //Loop through the work items linked to this work item for (int i = 0; i < wi.WorkItemLinks.Count; i++) { if (_full) { ProcessLinks(wi, wi.WorkItemLinks[i], s); } else { if (IsLinkSelected(wi.WorkItemLinks[i].LinkTypeEnd.Name)) { ProcessLinks(wi, wi.WorkItemLinks[i], s); } } } if (_full) { GetChangesets(wi, s); } else { if (IsLinkSelected("Changesets")) { GetChangesets(wi, s); } } if (s.WorkItemTypeName == "Test Case") { if (_full) { GetTestResults(s, wi.Project.Name); } else { if (IsLinkSelected("Test Results")) { GetTestResults(s, wi.Project.Name); } } } }
/// <summary> /// The work item to process /// </summary> /// <param name="wi"></param> private void ProcessWorkItemCS(WorkItem wi) { //Get a reference to or add the wi to the workitemstub list WorkItemStub s = CheckStub(wi); //Loop through the work items linked to this work item for (int i = 0; i < wi.WorkItemLinks.Count; i++) { if (IsLinkSelected(wi.WorkItemLinks[i].LinkTypeEnd.Name)) { int targetID = wi.WorkItemLinks[i].TargetId; //Check to see if the work item is in the list of work items and if not, add it by //calling this method recursively. If it is in the list of work items then we've already //seen this work item and we just have to figure out how it is linked to this work item WorkItemStub result = _workItemStubs.Find( delegate(WorkItemStub stub) { return(stub.ID == targetID); } ); //If the work item hasn't been processed yet, process it if (result == null) { ProcessWorkItemCS(_wis.GetWorkItem(targetID)); } s.Related.Add(new WorkItemRelationship() { ID = targetID, Relationship = wi.WorkItemLinks[i].LinkTypeEnd.Name }); } } if (IsLinkSelected("Changesets")) { GetChangesets(wi, s); } if (IsLinkSelected("Test Results")) { //Get the test results if this is a test case if (s.WorkItemTypeName == "Test Case") { GetTestResults(s, wi.Project.Name); } } }
/// <summary> /// Gets all work item stubs related to a given work item stub /// </summary> /// <param name="stub">The work item to get relationships for</param> /// <returns>A list of related work item stubs</returns> private List <WorkItemStub> GetRelatedWorkItems(WorkItemStub stub) { List <WorkItemStub> related = new List <WorkItemStub>(); for (int i = 0; i < _workItemStubs.Count; i++) { for (int k = 0; k < _workItemStubs[i].Related.Count; k++) { if ((_workItemStubs[i].Related[k].ID == stub.ID) && (_workItemStubs[i].Related[k].End == "Child")) { related.Add(_workItemStubs[i]); } } } return(related); }
/// <summary> /// This method takes a work item and examines it's relationships to determine what /// the root work item is. The use of this method is in dependency analysis which /// takes the following ReqA --> TaskB --> ChangesetC and changes it to /// ReqA --> Changeset C. This base work item has changesets otherwise we would /// not be processing it. For our purposes we would be starting with TaskB and /// looking for ReqA or some other parent /// </summary> /// <param name="wi">The work item to discover the parent of</param> private void GetWorkItemParent(WorkItemStub stub) { //The rules for discovery are as follows: //1. Walk the parent/child relationship from the reverse to the forward node //2. Check the related work item ONLY when going from a Bug to a Test Case // - never the reverse or you get trapped in a recursive loop //3. Check the affected by/affects from the reverse to the forward (in other // words the standard relationship is a Requiremenet is Affected By a // Change Request which has an associated changeset or child task WorkItemStub s = null; //stores the related work item stubs bool found = false; //indicates if we found a valid link to persue //Because of how the relationships are constructed, only one end of the relationship has //the actual link to the relationship. For example, Story1 has relationships with Task1 //and Task2 but Task1 and Task2 don't know anything about Story1. So, when we are going //through this list, we have to determine which other work items are related to the work //item we're looking at right now. //NOTE I may have to come back to this because it may be a fallacy that just because //story1 is related to task1 and task2 doesn't mean that there isn't a "story3" that //is the parent of Story1 //This returns a list of parent work items that are related to thsi work item. List <WorkItemStub> r = GetRelatedWorkItems(stub); for (int i = 0; i < r.Count; i++) { s = GetStub(r[i].ID); GetWorkItemParent(s); found = true; } //If we haven't found any other links that are parent/child then this //must be the root that we are associating the changesets with if (!found) { if (_tempStub != stub) { //Associate the changeset with this work item for (int k = 0; k < _tempStub.Changesets.Count; k++) { stub.Changesets.Add(_tempStub.Changesets[k]); } } } }
private void Process(WorkItem[] workItems) { _workItemStubs = new List <WorkItemStub>(); _allNodeTypes = new List <string>(); //Get the full list of link types for assigning category relationships _links = LoadLinkTypes(_projectName); //Process all work items for (int i = 0; i < workItems.Length; i++) { ProcessWorkItemCS(workItems[i]); } //The colors for all other node types (i.e. not work item types) _allNodeTypes.Add("Changeset"); _allNodeTypes.Add("Iteration"); _allNodeTypes.Add("File"); _allNodeTypes.Add("Test Plan"); _allNodeTypes.Add("Test Run"); _allNodeTypes.Add("Test Result"); //Process the changesets so they are also related to the actual root work item if (_dependendyAnalysis) { //Only process work items that have changesets for (int i = 0; i < _workItemStubs.Count; i++) { if (_workItemStubs[i].Changesets.Count > 0) { _tempStub = _workItemStubs[i]; GetWorkItemParent(_tempStub); } } } //Output the results WriteChangesetInfo(_outputFile, _projectName); }
/// <summary> /// Traces the path of the work item to it's root /// </summary> /// <param name="stub">The work item stub to trace</param> private void GetRootWorkItem(WorkItemStub stub) { WorkItemStub s = null; for (int i = 0; i < stub.Related.Count; i++) { s = _workItemStubs.Find( delegate(WorkItemStub wiStub) { return(wiStub.ID == stub.Related[i].ID); } ); if ((s.WorkItemTypeName == "User Story") || (s.WorkItemTypeName == "Requirement")) { _analysisStubs.Add(s); } else { GetRootWorkItem(s); } } }
/// <summary> /// Retrieves changesets associated with a work item /// </summary> /// <param name="wi">The work item to retrieve changesets for</param> /// <param name="stub">The work item stub to add them to</param> private void GetChangesets(WorkItem wi, WorkItemStub stub) { //Loop through all of the links in the work item. Note that this is the links //not the work item links so this includes things like hyperlinks, versioned items //and changeset links for (int i = 0; i < wi.Links.Count; i++) { //Determine if this is an external link which is an indication of a changeset link if (wi.Links[i].BaseType == BaseLinkType.ExternalLink) { int cs_id; ExternalLink ex = (ExternalLink)wi.Links[i]; //Try to get the changeset ID by parsing the end of the linked artifact URI //For a changeset this will always be a numeric value if (int.TryParse(ex.LinkedArtifactUri.Substring(ex.LinkedArtifactUri.LastIndexOf('/') + 1), out cs_id)) { //It is a changeset, validate that we haven't processed it already ChangesetStub c = stub.Changesets.Find( delegate(ChangesetStub s) { return s.ID == cs_id; } ); //It wasn't found, process it if (c == null) { //It is a changeset so get the specific changeset Changeset cs = _vcs.GetChangeset(cs_id); ChangesetStub csStub = new ChangesetStub(); csStub.ID = cs_id; //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { //Add the files to the changeset stub FileChangeInfo fc = new FileChangeInfo(); fc.ChangeType = cs.Changes[j].ChangeType.ToString(); fc.FullPath = cs.Changes[j].Item.ServerItem; csStub.Files.Add(fc); //Check to see if we have added this file to the master list, //if we haven't, add it if (!_allFiles.Contains(fc.FileName)) _allFiles.Add(fc.FileName); } stub.Changesets.Add(csStub); //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { ChangesetFilesToWorkItems(cs.Changes[j].Item.ServerItem); } } } } } }
/// <summary> /// Get the results associated with a test case /// </summary> /// <param name="stub">The work item to get the results for</param> private void GetTestResults(WorkItemStub stub, string project) { //Return all of the test results in which this test case was executed string query = string.Format("SELECT * FROM TestResult WHERE TestCaseId = {0}", stub.ID); int planId = 0; //Get the list of results for the test case foreach (ITestCaseResult tcr in _tmp.TestResults.Query(query)) { #region Get the Test Plan string runQuery = string.Format("SELECT * FROM TestRun WHERE TestRunId = {0}", tcr.TestRunId); //There should only be one value returned so just get the first one foreach (ITestRun tr in _tms.QueryTestRuns(runQuery)) { planId = tr.TestPlanId; break; } //Is this part of a test plan that we already have? TestPlanInfo plan = _testPlans.Find( delegate(TestPlanInfo tpi) { return(tpi.TestPlanID == planId); } ); //If not, add it if (plan == null) { string planQuery = string.Format("SELECT * FROM TestPlan WHERE PlanId = {0}", planId); foreach (ITestPlan testPlan in _tmp.TestPlans.Query(planQuery)) { plan = new TestPlanInfo() { TestPlanID = planId, TestPlanName = testPlan.Name }; _testPlans.Add(plan); break; } } #endregion //Check to see if we've added the test run already bool found = false; for (int k = 0; k < plan.TestRuns.Count; k++) { if (plan.TestRuns[k].ID == tcr.TestRunId) { found = true; } } //If not, add it if (!found) { plan.TestRuns.Add(new TestRunStub() { ID = tcr.TestRunId, Url = GetURL(UrlType.TestRun, tcr.TestRunId, 0, project) }); } //add the results TestResultStub resultStub = new TestResultStub(); resultStub.TestPlan = plan; resultStub.TestCaseID = tcr.TestCaseId; resultStub.TestResultID = tcr.TestResultId; resultStub.TestRunID = tcr.TestRunId; resultStub.Outcome = tcr.Outcome; resultStub.Url = GetURL(UrlType.TestResult, tcr.TestRunId, tcr.TestResultId, project); stub.TestResults.Add(resultStub); } }
/// <summary> /// Retrieves changesets associated with a work item /// </summary> /// <param name="wi">The work item to retrieve changesets for</param> /// <param name="stub">The work item stub to add them to</param> private void GetChangesets(WorkItem wi, WorkItemStub stub) { //Loop through all of the links in the work item. Note that this is the links //not the work item links so this includes things like hyperlinks, versioned items //and changeset links for (int i = 0; i < wi.Links.Count; i++) { //Determine if this is an external link which is an indication of a changeset link if (wi.Links[i].BaseType == BaseLinkType.ExternalLink) { int cs_id; ExternalLink ex = (ExternalLink)wi.Links[i]; //We have a valid changeset link type if (ex.ArtifactLinkType.Equals(_wis.RegisteredLinkTypes[ArtifactLinkIds.Changeset])) { //Get the ID of the changeset ArtifactId artifact = LinkingUtilities.DecodeUri(ex.LinkedArtifactUri); cs_id = Convert.ToInt32(artifact.ToolSpecificId); //It is a changeset, validate that we haven't processed it already ChangesetStub c = stub.Changesets.Find( delegate(ChangesetStub s) { return(s.ID == cs_id); } ); //It wasn't found, process it if (c == null) { //It is a changeset so get the specific changeset Changeset cs = _vcs.GetChangeset(cs_id); ChangesetStub csStub = new ChangesetStub(); csStub.ID = cs_id; //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { //Add the files to the changeset stub FileChangeInfo fc = new FileChangeInfo(); fc.ChangeType = cs.Changes[j].ChangeType.ToString(); fc.FullPath = cs.Changes[j].Item.ServerItem; csStub.Files.Add(fc); //Check to see if we have added this file to the master list, //if we haven't, add it if (!_allFiles.Contains(fc.FileName)) { _allFiles.Add(fc.FileName); } } stub.Changesets.Add(csStub); //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { ChangesetFilesToWorkItems(cs.Changes[j].Item.ServerItem); } } } } } }
/// <summary> /// Gets the stub associated with the work item if it exists, otherwise a new one is /// created, added to the collection and returned /// </summary> /// <param name="wi">The Work Item to check</param> /// <returns>The associated WorkItemStub</returns> private WorkItemStub CheckStub(WorkItem wi) { //Perform a find on the ID, if it is found, s is populated WorkItemStub s = GetStub((int)wi.Fields[CoreField.Id].Value); //If it isn't found, create a new work item stub if (s == null) { s = new WorkItemStub(); s.ID = (int)wi.Fields[CoreField.Id].Value; s.Title = wi.Fields[CoreField.Title].Value.ToString(); s.WorkItemTypeName = wi.Fields[CoreField.WorkItemType].Value.ToString(); s.Iteration = wi.Fields[CoreField.IterationPath].Value.ToString(); if (!_allNodeTypes.Contains(s.WorkItemTypeName)) _allNodeTypes.Add(s.WorkItemTypeName); //Check to see if the iteration exists in the list of iterations and add it if it doesn't if (!_iterations.Contains(s.Iteration)) _iterations.Add(s.Iteration); _workItemStubs.Add(s); } return s; }
/// <summary> /// Retrieves changesets associated with a work item /// </summary> /// <param name="wi">The work item to retrieve changesets for</param> /// <param name="stub">The work item stub to add them to</param> private void GetChangesets(WorkItem wi, WorkItemStub stub) { //Loop through all of the links in the work item. Note that this is the links //not the work item links so this includes things like hyperlinks, versioned items //and changeset links for (int i = 0; i < wi.Links.Count; i++) { //Determine if this is an external link which is an indication of a changeset link if (wi.Links[i].BaseType == BaseLinkType.ExternalLink) { int cs_id; ExternalLink ex = (ExternalLink)wi.Links[i]; //We have a valid changeset link type if (ex.ArtifactLinkType.Equals(_wis.RegisteredLinkTypes[ArtifactLinkIds.Changeset])) { //Get the ID of the changeset ArtifactId artifact = LinkingUtilities.DecodeUri(ex.LinkedArtifactUri); cs_id = Convert.ToInt32(artifact.ToolSpecificId); //It is a changeset, validate that we haven't processed it already ChangesetStub c = stub.Changesets.Find( delegate(ChangesetStub s) { return s.ID == cs_id; } ); //It wasn't found, process it if (c == null) { //It is a changeset so get the specific changeset Changeset cs = _vcs.GetChangeset(cs_id); ChangesetStub csStub = new ChangesetStub(); csStub.ID = cs_id; //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { //Add the files to the changeset stub FileChangeInfo fc = new FileChangeInfo(); fc.ChangeType = cs.Changes[j].ChangeType.ToString(); fc.FullPath = cs.Changes[j].Item.ServerItem; csStub.Files.Add(fc); //Check to see if we have added this file to the master list, //if we haven't, add it if (!_allFiles.Contains(fc.FileName)) _allFiles.Add(fc.FileName); } stub.Changesets.Add(csStub); //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { ChangesetFilesToWorkItems(cs.Changes[j].Item.ServerItem); } } } } } }
/// <summary> /// Processes a relationship between two work items /// </summary> /// <param name="wi">The source work item</param> /// <param name="wiLink">The link to the target work item</param> /// <param name="s">The work item stub that corrosponds to the source work item</param> private void ProcessLinks(WorkItem wi, WorkItemLink wiLink, WorkItemStub s) { int targetID = wiLink.TargetId; //Check to see if the work item that is related to this one is in the list of work items and if not, add it by //calling this method recursively. If it is in the list of work items then we've already //seen this work item and we just have to figure out how it is linked to this work item WorkItemStub result = _workItemStubs.Find( delegate(WorkItemStub stub) { return(stub.ID == targetID); } ); //If the work item hasn't been processed yet, process it if (result == null) { ProcessWorkItemCS(_wis.GetWorkItem(targetID)); } //Check to see if the ID and relationship match (we can have more than one relationship between two work items //for example, we could have a parent/child relationship and also a predecessor/successor relationship WorkItemRelationship result1 = s.Related.Find( delegate(WorkItemRelationship stub) { return(stub.ToString() == targetID.ToString() + wiLink.LinkTypeEnd.Name); } ); if (result1 == null) { bool found = false; //Before we add this relationship in, make sure we have never added this relationship anywhere at all //so we make sure each relationship (forward/reverse end of the same relationship) is unique in the //entire result set. for (int j = 0; j < _workItemStubs.Count; j++) { if (_workItemStubs[j].ID == targetID) { for (int k = 0; k < _workItemStubs[j].Related.Count; k++) { if (_workItemStubs[j].Related[k].ID == wi.Id) { found = true; break; } } } if (found) { break; } } //If we didn't find an existing relationship, make sure we add it to the //work item at the reverse end of the relationship. For example, in a Parent/ //Child relationship the Child is the Forward end of the relationship and //Parent is the reverse end of the relationship. We need to add this relationship //to the Parent to say that the parent has children so when the links are //written out to the DGML they point the right direction if (!found) { //get the relationship TempLinkType2 t = GetRelationship(wiLink.LinkTypeEnd.Name); //Determine if this is the forward or reverse end of the relationship if (t.Reverse == wiLink.LinkTypeEnd.Name) { //This is the reverse end of the relationship so add it, otherwise skip it altogether s.Related.Add(new WorkItemRelationship() { ID = targetID, End = wiLink.LinkTypeEnd.Name, Relationship = GetRelationship(wiLink.LinkTypeEnd.Name) }); } } } }
/// <summary> /// Gets all work item stubs related to a given work item stub /// </summary> /// <param name="stub">The work item to get relationships for</param> /// <returns>A list of related work item stubs</returns> private List<WorkItemStub> GetRelatedWorkItems(WorkItemStub stub) { List<WorkItemStub> related = new List<WorkItemStub>(); for (int i = 0; i < _workItemStubs.Count; i++) { for (int k = 0; k < _workItemStubs[i].Related.Count; k++) { if ((_workItemStubs[i].Related[k].ID == stub.ID) && (_workItemStubs[i].Related[k].End == "Child")) { related.Add(_workItemStubs[i]); } } } return related; }
/// <summary> /// Get the results associated with a test case /// </summary> /// <param name="stub">The work item to get the results for</param> private void GetTestResults(WorkItemStub stub, string project) { //Return all of the test results in which this test case was executed string query = string.Format("SELECT * FROM TestResult WHERE TestCaseId = {0}", stub.ID); int planId = 0; //Get the list of results for the test case foreach (ITestCaseResult tcr in _tmp.TestResults.Query(query)) { #region Get the Test Plan string runQuery = string.Format("SELECT * FROM TestRun WHERE TestRunId = {0}", tcr.TestRunId); //There should only be one value returned so just get the first one foreach (ITestRun tr in _tms.QueryTestRuns(runQuery)) { planId = tr.TestPlanId; break; } //Is this part of a test plan that we already have? TestPlanInfo plan = _testPlans.Find( delegate(TestPlanInfo tpi) { return tpi.TestPlanID == planId; } ); //If not, add it if (plan == null) { string planQuery = string.Format("SELECT * FROM TestPlan WHERE PlanId = {0}", planId); foreach (ITestPlan testPlan in _tmp.TestPlans.Query(planQuery)) { plan = new TestPlanInfo() { TestPlanID = planId, TestPlanName = testPlan.Name }; _testPlans.Add(plan); break; } } #endregion //Check to see if we've added the test run already bool found = false; for (int k = 0; k < plan.TestRuns.Count; k++) { if (plan.TestRuns[k].ID == tcr.TestRunId) { found = true; } } //If not, add it if (!found) plan.TestRuns.Add(new TestRunStub() { ID = tcr.TestRunId, Url = GetURL(UrlType.TestRun, tcr.TestRunId, 0, project) }); //add the results TestResultStub resultStub = new TestResultStub(); resultStub.TestPlan = plan; resultStub.TestCaseID = tcr.TestCaseId; resultStub.TestResultID = tcr.TestResultId; resultStub.TestRunID = tcr.TestRunId; resultStub.Outcome = tcr.Outcome; resultStub.Url = GetURL(UrlType.TestResult, tcr.TestRunId, tcr.TestResultId, project); stub.TestResults.Add(resultStub); } }
/// <summary> /// This method takes a work item and examines it's relationships to determine what /// the root work item is. The use of this method is in dependency analysis which /// takes the following ReqA --> TaskB --> ChangesetC and changes it to /// ReqA --> Changeset C. This base work item has changesets otherwise we would /// not be processing it. For our purposes we would be starting with TaskB and /// looking for ReqA or some other parent /// </summary> /// <param name="wi">The work item to discover the parent of</param> private void GetWorkItemParent(WorkItemStub stub) { //The rules for discovery are as follows: //1. Walk the parent/child relationship from the reverse to the forward node //2. Check the related work item ONLY when going from a Bug to a Test Case // - never the reverse or you get trapped in a recursive loop //3. Check the affected by/affects from the reverse to the forward (in other // words the standard relationship is a Requiremenet is Affected By a // Change Request which has an associated changeset or child task WorkItemStub s = null; //stores the related work item stubs bool found = false; //indicates if we found a valid link to persue //Because of how the relationships are constructed, only one end of the relationship has //the actual link to the relationship. For example, Story1 has relationships with Task1 //and Task2 but Task1 and Task2 don't know anything about Story1. So, when we are going //through this list, we have to determine which other work items are related to the work //item we're looking at right now. //NOTE I may have to come back to this because it may be a fallacy that just because //story1 is related to task1 and task2 doesn't mean that there isn't a "story3" that //is the parent of Story1 //This returns a list of parent work items that are related to thsi work item. List<WorkItemStub> r = GetRelatedWorkItems(stub); for (int i = 0; i < r.Count; i++) { s = GetStub(r[i].ID); GetWorkItemParent(s); found = true; } //If we haven't found any other links that are parent/child then this //must be the root that we are associating the changesets with if (!found) { if (_tempStub != stub) { //Associate the changeset with this work item for (int k = 0; k < _tempStub.Changesets.Count; k++) { stub.Changesets.Add(_tempStub.Changesets[k]); } } } }
/// <summary> /// Retrieves changesets associated with a work item /// </summary> /// <param name="wi">The work item to retrieve changesets for</param> /// <param name="stub">The work item stub to add them to</param> private void GetChangesets(WorkItem wi, WorkItemStub stub) { //Loop through all of the links in the work item. Note that this is the links //not the work item links so this includes things like hyperlinks, versioned items //and changeset links for (int i = 0; i < wi.Links.Count; i++) { //Determine if this is an external link which is an indication of a changeset link if (wi.Links[i].BaseType == BaseLinkType.ExternalLink) { int cs_id; ExternalLink ex = (ExternalLink)wi.Links[i]; //Try to get the changeset ID by parsing the end of the linked artifact URI //For a changeset this will always be a numeric value if (int.TryParse(ex.LinkedArtifactUri.Substring(ex.LinkedArtifactUri.LastIndexOf('/') + 1), out cs_id)) { //It is a changeset, validate that we haven't processed it already ChangesetStub c = stub.Changesets.Find( delegate(ChangesetStub s) { return(s.ID == cs_id); } ); //It wasn't found, process it if (c == null) { //It is a changeset so get the specific changeset Changeset cs = _vcs.GetChangeset(cs_id); ChangesetStub csStub = new ChangesetStub(); csStub.ID = cs_id; //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { //Add the files to the changeset stub FileChangeInfo fc = new FileChangeInfo(); fc.ChangeType = cs.Changes[j].ChangeType.ToString(); fc.FullPath = cs.Changes[j].Item.ServerItem; csStub.Files.Add(fc); //Check to see if we have added this file to the master list, //if we haven't, add it if (!_allFiles.Contains(fc.FileName)) { _allFiles.Add(fc.FileName); } } stub.Changesets.Add(csStub); //Loop through the files in the changeset which is represented by the Changes for (int j = 0; j < cs.Changes.Count(); j++) { ChangesetFilesToWorkItems(cs.Changes[j].Item.ServerItem); } } } } } }
/// <summary> /// Traces the path of the work item to it's root /// </summary> /// <param name="stub">The work item stub to trace</param> private void GetRootWorkItem(WorkItemStub stub) { WorkItemStub s = null; for (int i = 0; i < stub.Related.Count; i++) { s = _workItemStubs.Find( delegate(WorkItemStub wiStub) { return wiStub.ID == stub.Related[i].ID; } ); if ((s.WorkItemTypeName == "User Story") || (s.WorkItemTypeName == "Requirement")) _analysisStubs.Add(s); else GetRootWorkItem(s); } }
/// <summary> /// Processes a relationship between two work items /// </summary> /// <param name="wi">The source work item</param> /// <param name="wiLink">The link to the target work item</param> /// <param name="s">The work item stub that corrosponds to the source work item</param> private void ProcessLinks(WorkItem wi, WorkItemLink wiLink, WorkItemStub s) { int targetID = wiLink.TargetId; //Check to see if the work item that is related to this one is in the list of work items and if not, add it by //calling this method recursively. If it is in the list of work items then we've already //seen this work item and we just have to figure out how it is linked to this work item WorkItemStub result = _workItemStubs.Find( delegate(WorkItemStub stub) { return stub.ID == targetID; } ); //If the work item hasn't been processed yet, process it if (result == null) ProcessWorkItemCS(_wis.GetWorkItem(targetID)); //Check to see if the ID and relationship match (we can have more than one relationship between two work items //for example, we could have a parent/child relationship and also a predecessor/successor relationship WorkItemRelationship result1 = s.Related.Find( delegate(WorkItemRelationship stub) { return stub.ToString() == targetID.ToString() + wiLink.LinkTypeEnd.Name; } ); if (result1 == null) { bool found = false; //Before we add this relationship in, make sure we have never added this relationship anywhere at all //so we make sure each relationship (forward/reverse end of the same relationship) is unique in the //entire result set. for (int j = 0; j < _workItemStubs.Count; j++) { if (_workItemStubs[j].ID == targetID) { for (int k = 0; k < _workItemStubs[j].Related.Count; k++) { if (_workItemStubs[j].Related[k].ID == wi.Id) { found = true; break; } } } if (found) break; } //If we didn't find an existing relationship, make sure we add it to the //work item at the reverse end of the relationship. For example, in a Parent/ //Child relationship the Child is the Forward end of the relationship and //Parent is the reverse end of the relationship. We need to add this relationship //to the Parent to say that the parent has children so when the links are //written out to the DGML they point the right direction if (!found) { //get the relationship TempLinkType2 t = GetRelationship(wiLink.LinkTypeEnd.Name); //Determine if this is the forward or reverse end of the relationship if (t.Reverse == wiLink.LinkTypeEnd.Name) { //This is the reverse end of the relationship so add it, otherwise skip it altogether s.Related.Add(new WorkItemRelationship() { ID = targetID, End = wiLink.LinkTypeEnd.Name, Relationship = GetRelationship(wiLink.LinkTypeEnd.Name) }); } } } }
private void Process(WorkItem[] workItems) { _workItemStubs = new List<WorkItemStub>(); _allNodeTypes = new List<string>(); //Get the full list of link types for assigning category relationships _links = LoadLinkTypes(_projectName); //Process all work items for (int i = 0; i < workItems.Length; i++) { ProcessWorkItemCS(workItems[i]); } //The colors for all other node types (i.e. not work item types) _allNodeTypes.Add("Changeset"); _allNodeTypes.Add("Iteration"); _allNodeTypes.Add("File"); _allNodeTypes.Add("Test Plan"); _allNodeTypes.Add("Test Run"); _allNodeTypes.Add("Test Result"); //Process the changesets so they are also related to the actual root work item if (_dependendyAnalysis) { //Only process work items that have changesets for (int i = 0; i < _workItemStubs.Count; i++) { if (_workItemStubs[i].Changesets.Count > 0) { _tempStub = _workItemStubs[i]; GetWorkItemParent(_tempStub); } } } //Output the results WriteChangesetInfo(_outputFile, _projectName); }