2014-02-18 7 views
1

저는 TFS 2012와 스크럼 프로세스 템플릿을 사용하고 있습니다.스프린트가 TFS에서 스프린트를 시작한 후에 추가 된 트래킹 사례

나는 그 스프린트의 타임 라인에서 특정 시점 이후에 스프린트에 추가 된 이야기를보고 싶다.

일반적으로 중간 스프린트 "미니"계획 세션이 있습니다. 이를 통해 팀 전체에 기존 작업 부하의 균형을 재조정 할 수 있지만 예상보다 많은 작업을 완료하면 PBI/사용자 사례를 스프린트에 추가 할 수 있습니다.

이야기의 반복 경로가 변경된 것을 확인하기 위해 쿼리하는 방법을 볼 수 없습니다. 이것이 가능한가?

+0

이 도움이 확실하지만, 역사적 감사 데이터를하지 않음 (변화는 시간이 지남에) 나는 쉽게 직접 TFS 데이터웨어 하우스를 조회 할 수 발견했다. 내가 원하는 데이터에 대한 SQL 쿼리를 작성하고 Excel에 임베드하고, 액세스하기 쉽고, 새로 고침하기 쉽습니다.이 옵션을 선택하는 경우 찾고있는보기가 WorkItemHistoryView입니다. –

답변

2

이 작업을 수행하려면 TFS API를 사용하여 사용자 지정 응용 프로그램을 만들어야합니다.

var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(options.TfsUri)); 

    var workItemStore = tfs.GetService<WorkItemStore>(); 
    var project = workItemStore.Projects[options.ProjectName]; 
    var projectIterationPath = string.Format("{0}\\{1}", project.Name, options.IterationPath); 

    var items = project.Store.Query(
      "SELECT [System.Id] FROM WorkItems WHERE [System.WorkItemType] IN ('User Story', 'Product Backlog Item', 'Bug') AND [System.IterationPath] = '" + 
      projectIterationPath + "'"); 

그런 다음 당신이 (작업 완료 대 전체 작업을) 다양한 포인트 합계를 요약한다 :

var pointTotal = workItems 
     .Where(
      i => 
       i.Fields[effortField].Value != null && 
       decimal.TryParse(i.Fields[effortField].Value.ToString(), out temp)) 
     .Sum(i => decimal.Parse(i[effortField].ToString())); 

    var pointsCompleted = workItems 
     .Where(
      i => 
       (string.Compare(i.State, "done", true) == 0 || string.Compare(i.State, "closed", true) == 0) && 
       i.Fields[effortField].Value != null && 
       decimal.TryParse(i.Fields[effortField].Value.ToString(), out temp)) 
     .Sum(i => decimal.Parse(i[effortField].ToString())); 

그런 다음 당신이 필요

첫째, 당신은 관련 작업 항목 목록을 확보해야 시작 및 종료 반복 날짜에 대한 정보 얻기 :

var iterationSchedule = GetIterationSchedule(tfs, project.Uri.ToString(), 

    private static ScheduleInfo GetIterationSchedule(TfsTeamProjectCollection tfs, string projectUri, string iterationPath) 
    { 
     var css = tfs.GetService<ICommonStructureService4>(); 
     var structures = css.ListStructures(projectUri); 
     var iterations = structures.FirstOrDefault(s => s.StructureType.Equals("ProjectLifecycle")); 

     if (iterations != null) 
     { 
      string projectName = css.GetProject(projectUri).Name; 

      XmlElement iterationsTree = css.GetNodesXml(new[] {iterations.Uri}, true); 
      return GetIterationDates(iterationsTree.ChildNodes[0], projectName, iterationPath); 
     } 

     return null; 
    } 

    private static ScheduleInfo GetIterationDates(XmlNode node, string projectName, string iterationPath) 
    { 
     var targetIterationPath = string.Format("\\{0}\\Iteration\\{1}", projectName, iterationPath); 
     XElement targetIteration = null; 

     if (node != null) 
     { 
      var iterations = XDocument.Parse(node.InnerXml); 

      targetIteration = iterations.Descendants("Node") 
       .Where(n => n.Attribute("Path") != null && !string.IsNullOrEmpty(n.Attribute("Path").Value)) 
       .SingleOrDefault(n => string.Compare(n.Attribute("Path").Value, targetIterationPath, true) == 0); 
     } 

     if (targetIteration != null) 
     { 
      // Attempt to read the start and end dates if they exist. 
      string strStartDate = (targetIteration.Attribute("StartDate") != null) 
       ? targetIteration.Attribute("StartDate").Value 
       : null; 
      string strEndDate = (targetIteration.Attribute("FinishDate") != null) 
       ? targetIteration.Attribute("FinishDate").Value 
       : null; 

      DateTime? rStateDate = null, rEndDate = null; 

      if (!string.IsNullOrEmpty(strStartDate) && !string.IsNullOrEmpty(strEndDate)) 
      { 
       DateTime startDate; 
       if (DateTime.TryParse(strStartDate, out startDate)) 
        rStateDate = startDate; 

       DateTime endDate; 
       if (DateTime.TryParse(strEndDate, out endDate)) 
        rEndDate = endDate; 
      } 

      return new ScheduleInfo 
      { 
       IterationPath = iterationPath, 
       StartDate = rStateDate, 
       EndDate = rEndDate 
      }; 
     } 

     return null; 
    } 

마지막으로 모두 함께 스프린트에 대한 요약을 생성하십시오.

 foreach (var item in workItems) 
     { 
      var postSprintStartRevisions = (from r in item.Revisions.Cast<Revision>() 
       where r.Fields.Cast<Field>() 
         .Any(f => f.Name == "Revised Date" && ((DateTime) f.Value) >= postStartDate) 
        && r.Fields.Cast<Field>() 
         .Any(
          f => 
           f.Name == "Iteration Path" 
           && string.Compare(f.OriginalValue.ToString(), projectIterationPath, true) != 0 
           && string.Compare(f.Value.ToString(), projectIterationPath, true) == 0) 
       select r).ToArray(); 

      if (postSprintStartRevisions.Any() && item[effortField] != null) 
      { 
       pointsPostSprintStart += decimal.Parse(item[effortField].ToString()); 
      } 
     } 

코드가 예쁘지는 않지만 필자에게 필요한 것은 아닙니다.

사용법 :

내가 생각 무엇
Usage: pbitracker -TfsUri [uri] -ProjectName [name] -IterationPath [path] -b 3 

    -u, --TfsUri    Required. TFS Project Collection Uri. Ex: 
          http://tfs:8080/tfs/defaultcollection 

    -p, --ProjectName  Required. TFS Project Name. Ex: MyProject 

    -i, --IterationPath  Required. Iteration Path. Ex: 'GA\Sprint 3' 

    -b, --StartDateBuffer (Default: 3) Number of days after the start date to 
          consider the worked as added post-start 

    --help     Display this help screen. 

는 "후 시작을 추가은"응용 프로그램에 전달 옵션을 기반으로합니다. 기본적으로 3 일로 기본 설정되어 있으므로 스프린트가 월요일에 시작되어 목요일에 작업을 추가하면 해당 작업은 시작 후 추가 된 지점으로 간주됩니다. GitHub 또는 CodePlex에서이 문제를 해결해보고 답변을 업데이트하겠습니다.

예 출력 :

Querying with the following options... 
TFS Uri:    http://tfs:8080/tfs/DefaultCollection 
Project Name:   MyProject 
Iteration Path:   GA\Sprint 16 
Please wait... 


Iteration Start Date:     2/24/2014 12:00:00 AM 
Iteration End Date:      3/7/2014 12:00:00 AM 
Iteration Point Total:     168 
Iteration Point Total Completed:  168 
Iteration Points Starting Points:  162 
Iteration Points Added Post-Start:  6 
0

나는 이것을 할 수있는 많은 방법이 있다고 생각합니다. 하지만 내가 한 것은 간단한 쿼리를 만드는 것입니다. 아래 스크린 샷에서 TFS2012 ALM VM과 FabrikamFiber 샘플을 사용했습니다. 쿼리 및 결과 창 구성을 볼 수 있습니다.

마지막 항목은 스프린트가 시작된 후 제가 스프린트로 가져온 제품 백 로그 항목을 보여줍니다. 이는 제가 생각한 것입니다. '변경 날짜'값이 스프린트 시작 날짜보다 늦어지는 것을 볼 수 있습니다.

enter image description here

이하, 그것을 즐겨 찾기에 해당 쿼리를 추가하는 간단한 작업입니다. 반복 경로를 변경하는 것을 잊지 마십시오!

+0

변경된 항목이 * 작업 항목의 * 변경 사항에 업데이트되지 않습니까? – RMD

+0

예. 여기에는 다른 필드에 업데이트 된 항목이 포함됩니다. –