显示 Visual Studio 联机工作项周期时间
Show Visual Studio Online Work Item Cycle Times
理想情况下,我想通过 Power BI 在线计算 Visual Studio 中产品待办列表项表示的整个价值流的周期时间。 (然后我很想获得每个状态的时间,即它处于 "New" 状态多长时间,或者它停留在 "Committed" 状态多长时间。)
首先,我对使用代表产品积压项目 created date
和 closed date
之间的时间的计算值感兴趣。在此之后,我热衷于找到值的分布。
product backlog item time between created timestamp to closed timestamp
将是一个起点,但这当然显示 "queued duration minutes by title"。
大多数其他尝试的结果是:
Can’t determine relationships between the fields
有没有办法获得一些周期时间的指示?
假设每一行都有创建日期和关闭日期,您可以使用 power query duration 函数来获取两个日期之间的差异。
https://msdn.microsoft.com/en-us/library/mt296613.aspx
更新:在调查之后(请参阅下面我的评论)我意识到构建您需要的查询需要一些奥林匹克级别的查询技巧。所以我为你创建了它 :)。以下内容适用于 Power BI 桌面,但由于某种原因在 PowerBI.com 中没有刷新(我正在检查)。要完成这项工作,您需要将您的 VSO 帐户和查询 ID 放入 ConnectionInfo 记录中。
建议设置备用凭据而不是使用 BASIC 身份验证。
您可以通过将共享查询保存到您的 VSO 来获取 QueryID,然后使用 curl 通过查询检索 ID:
//Replace YOURACCOUNT and YOURPROJECT with correct values below
curl -u username:password https://YOURACCOUNT.visualstudio.com/DefaultCollection/YOURPROJECT/_apis/wit/queries?$depth=1&api-version=1.0
然后您可以使用以下查询(创建一个空白查询并将其粘贴到 Power BI Desktop 的高级编辑器中)。您可能需要调整从 "workitems =" 开始的一些步骤,因为您的查询可能包含与我的查询不同的字段。如果您 return 创建、解决和关闭日期,我使用的持续时间计算应该适合您。在 Power BI Desktop 中接受质询并提供所需凭据时,您会将身份验证设置为 "Basic"。
let
//TODO: replace YOURACCOUNT and YOURQUERYID below
ConnectionInfo = [account = "YOURACCOUNT.visualstudio.com", queryID="YOURQUERYID"],
account = Record.FieldValues(ConnectionInfo){0},
rootQuery = let
queryID = Record.FieldValues(ConnectionInfo){1},
query = "https://" & account & "/DefaultCollection/PowerBIClients/_apis/wit/wiql/" & queryID,
Source = Json.Document(Web.Contents(query))
in
Source,
#"INT-columns" = let
Source = rootQuery,
columns = Source[columns],
#"Converted to Table" = Table.FromList(columns, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"referenceName", "name", "url"}, {"referenceName", "name", "url"})
in
#"Expanded Column1",
#"RAW-workitems" = let
Source = rootQuery,
workItems = Source[workItems],
#"Converted to Table" = Table.FromList(workItems, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "url"}, {"id", "url"})
in
#"Expanded Column1",
#"INT-columnClause" = let
Source = #"INT-columns",
colNames = Table.RemoveColumns(Source,{"name", "url"}),
list = Table.ToList(colNames),
joined = Text.Combine(list, ",")
in
joined,
#"INT-workitemsToGet" = let
Source = #"RAW-workitems",
col = Table.RemoveColumns(Source,{"url"}),
#"Changed Type" = Table.TransformColumnTypes(col,{{"id", type text}}),
list = Table.ToList(#"Changed Type"),
l = List.Count(list),
limits = List.Generate(()=>0, each _ < l, each _ + 100),
#"Converted to Table" = Table.FromList(limits, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "iterations"}}),
#"Added Custom" = Table.AddColumn(#"Renamed Columns", "itemsToGet", each List.Range(list, [iterations], 100)),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "itemsToGetString", each Text.Combine([itemsToGet], ",")),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"iterations", "itemsToGet"})
in
#"Removed Columns",
#"INT-workitemRequests" = let
Source = #"INT-workitemsToGet",
#"Added Custom" = Table.AddColumn(Source, "requests", each "https://" & account & "/DefaultCollection/_apis/wit/workitems?ids=" & [itemsToGetString] & "&fields=" & #"INT-columnClause"),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"itemsToGetString"})
in
#"Removed Columns",
workitems = let
#"INT-workitemsRequests (2)" = let
Source = #"INT-workitemRequests",
results = Table.AddColumn(Source, "Results", each Json.Document(Web.Contents([requests]))),
out = 1
in
results,
#"Removed Columns" = Table.RemoveColumns(#"INT-workitemsRequests (2)",{"requests"}),
#"Expanded Results" = Table.ExpandRecordColumn(#"Removed Columns", "Results", {"count", "value"}, {"Results.count", "Results.value"}),
#"Expanded Results.value" = Table.ExpandListColumn(#"Expanded Results", "Results.value"),
#"Expanded Results.value1" = Table.ExpandRecordColumn(#"Expanded Results.value", "Results.value", {"id", "fields", "url"}, {"Results.value.id", "Results.value.fields", "Results.value.url"}),
#"Expanded Results.value.fields" = Table.ExpandRecordColumn(#"Expanded Results.value1", "Results.value.fields", {"System.Id", "System.WorkItemType", "System.State", "System.AssignedTo", "System.CreatedDate", "System.Title", "Microsoft.VSTS.Common.ResolvedDate", "Microsoft.VSTS.Common.ClosedDate"}, {"System.Id", "System.WorkItemType", "System.State", "System.AssignedTo", "System.CreatedDate", "System.Title", "Microsoft.VSTS.Common.ResolvedDate", "Microsoft.VSTS.Common.ClosedDate"}),
#"Removed Columns1" = Table.RemoveColumns(#"Expanded Results.value.fields",{"Results.count", "Results.value.id"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"Results.value.url", "WorkItemUrl"}}),
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"Microsoft.VSTS.Common.ResolvedDate", type datetime}, {"Microsoft.VSTS.Common.ClosedDate", type datetime}, {"System.CreatedDate", type datetime}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "DurationToResolved", each Duration.TotalDays([Microsoft.VSTS.Common.ResolvedDate] - [System.CreatedDate])),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "DurationToClosed", each Duration.TotalDays([Microsoft.VSTS.Common.ClosedDate] - [System.CreatedDate])),
#"Changed Type1" = Table.TransformColumnTypes(#"Added Custom1",{{"DurationToResolved", type number}, {"DurationToClosed", type number}})
in
#"Changed Type1"
in workitems
理想情况下,我想通过 Power BI 在线计算 Visual Studio 中产品待办列表项表示的整个价值流的周期时间。 (然后我很想获得每个状态的时间,即它处于 "New" 状态多长时间,或者它停留在 "Committed" 状态多长时间。)
首先,我对使用代表产品积压项目 created date
和 closed date
之间的时间的计算值感兴趣。在此之后,我热衷于找到值的分布。
product backlog item time between created timestamp to closed timestamp
将是一个起点,但这当然显示 "queued duration minutes by title"。
大多数其他尝试的结果是:
Can’t determine relationships between the fields
有没有办法获得一些周期时间的指示?
假设每一行都有创建日期和关闭日期,您可以使用 power query duration 函数来获取两个日期之间的差异。
https://msdn.microsoft.com/en-us/library/mt296613.aspx
更新:在调查之后(请参阅下面我的评论)我意识到构建您需要的查询需要一些奥林匹克级别的查询技巧。所以我为你创建了它 :)。以下内容适用于 Power BI 桌面,但由于某种原因在 PowerBI.com 中没有刷新(我正在检查)。要完成这项工作,您需要将您的 VSO 帐户和查询 ID 放入 ConnectionInfo 记录中。
建议设置备用凭据而不是使用 BASIC 身份验证。
您可以通过将共享查询保存到您的 VSO 来获取 QueryID,然后使用 curl 通过查询检索 ID:
//Replace YOURACCOUNT and YOURPROJECT with correct values below
curl -u username:password https://YOURACCOUNT.visualstudio.com/DefaultCollection/YOURPROJECT/_apis/wit/queries?$depth=1&api-version=1.0
然后您可以使用以下查询(创建一个空白查询并将其粘贴到 Power BI Desktop 的高级编辑器中)。您可能需要调整从 "workitems =" 开始的一些步骤,因为您的查询可能包含与我的查询不同的字段。如果您 return 创建、解决和关闭日期,我使用的持续时间计算应该适合您。在 Power BI Desktop 中接受质询并提供所需凭据时,您会将身份验证设置为 "Basic"。
let
//TODO: replace YOURACCOUNT and YOURQUERYID below
ConnectionInfo = [account = "YOURACCOUNT.visualstudio.com", queryID="YOURQUERYID"],
account = Record.FieldValues(ConnectionInfo){0},
rootQuery = let
queryID = Record.FieldValues(ConnectionInfo){1},
query = "https://" & account & "/DefaultCollection/PowerBIClients/_apis/wit/wiql/" & queryID,
Source = Json.Document(Web.Contents(query))
in
Source,
#"INT-columns" = let
Source = rootQuery,
columns = Source[columns],
#"Converted to Table" = Table.FromList(columns, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"referenceName", "name", "url"}, {"referenceName", "name", "url"})
in
#"Expanded Column1",
#"RAW-workitems" = let
Source = rootQuery,
workItems = Source[workItems],
#"Converted to Table" = Table.FromList(workItems, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "url"}, {"id", "url"})
in
#"Expanded Column1",
#"INT-columnClause" = let
Source = #"INT-columns",
colNames = Table.RemoveColumns(Source,{"name", "url"}),
list = Table.ToList(colNames),
joined = Text.Combine(list, ",")
in
joined,
#"INT-workitemsToGet" = let
Source = #"RAW-workitems",
col = Table.RemoveColumns(Source,{"url"}),
#"Changed Type" = Table.TransformColumnTypes(col,{{"id", type text}}),
list = Table.ToList(#"Changed Type"),
l = List.Count(list),
limits = List.Generate(()=>0, each _ < l, each _ + 100),
#"Converted to Table" = Table.FromList(limits, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "iterations"}}),
#"Added Custom" = Table.AddColumn(#"Renamed Columns", "itemsToGet", each List.Range(list, [iterations], 100)),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "itemsToGetString", each Text.Combine([itemsToGet], ",")),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"iterations", "itemsToGet"})
in
#"Removed Columns",
#"INT-workitemRequests" = let
Source = #"INT-workitemsToGet",
#"Added Custom" = Table.AddColumn(Source, "requests", each "https://" & account & "/DefaultCollection/_apis/wit/workitems?ids=" & [itemsToGetString] & "&fields=" & #"INT-columnClause"),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"itemsToGetString"})
in
#"Removed Columns",
workitems = let
#"INT-workitemsRequests (2)" = let
Source = #"INT-workitemRequests",
results = Table.AddColumn(Source, "Results", each Json.Document(Web.Contents([requests]))),
out = 1
in
results,
#"Removed Columns" = Table.RemoveColumns(#"INT-workitemsRequests (2)",{"requests"}),
#"Expanded Results" = Table.ExpandRecordColumn(#"Removed Columns", "Results", {"count", "value"}, {"Results.count", "Results.value"}),
#"Expanded Results.value" = Table.ExpandListColumn(#"Expanded Results", "Results.value"),
#"Expanded Results.value1" = Table.ExpandRecordColumn(#"Expanded Results.value", "Results.value", {"id", "fields", "url"}, {"Results.value.id", "Results.value.fields", "Results.value.url"}),
#"Expanded Results.value.fields" = Table.ExpandRecordColumn(#"Expanded Results.value1", "Results.value.fields", {"System.Id", "System.WorkItemType", "System.State", "System.AssignedTo", "System.CreatedDate", "System.Title", "Microsoft.VSTS.Common.ResolvedDate", "Microsoft.VSTS.Common.ClosedDate"}, {"System.Id", "System.WorkItemType", "System.State", "System.AssignedTo", "System.CreatedDate", "System.Title", "Microsoft.VSTS.Common.ResolvedDate", "Microsoft.VSTS.Common.ClosedDate"}),
#"Removed Columns1" = Table.RemoveColumns(#"Expanded Results.value.fields",{"Results.count", "Results.value.id"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"Results.value.url", "WorkItemUrl"}}),
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"Microsoft.VSTS.Common.ResolvedDate", type datetime}, {"Microsoft.VSTS.Common.ClosedDate", type datetime}, {"System.CreatedDate", type datetime}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "DurationToResolved", each Duration.TotalDays([Microsoft.VSTS.Common.ResolvedDate] - [System.CreatedDate])),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "DurationToClosed", each Duration.TotalDays([Microsoft.VSTS.Common.ClosedDate] - [System.CreatedDate])),
#"Changed Type1" = Table.TransformColumnTypes(#"Added Custom1",{{"DurationToResolved", type number}, {"DurationToClosed", type number}})
in
#"Changed Type1"
in workitems