Wednesday, 16 September 2015

Get a Build Note Between Given Two Builds Using PowerShell

A build associates work items from last good build to the current successful build. What if you want to find the associated work items between two builds, while having other successful builds in the middle.

image

Below script supports that. This is developed based on previous post script “Send Custom Build Notes with TFS Build Using PowerShell”.


  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
$tfsCollectionUrl = "http://yourtfsserver:8080/tfs/yourcollection"
$teamProject = "yourteamproject"
$versionControlPath = "$/yourteamproject/versioncontrolpath"
$buildDefinition = "yourbuilddefinitionname"
$fromBuildNumber = "frombuildnumber"
$toBuildNumber = "tobuildnumber"
$workItemStates = @("Resolved") # @("Resolved","New", "Active") @("Resolved") @("All")
$Recipients = @("user1@yourcompany.com","user2@yourcompany.com")
$EmailSender
= "sender@yourcompany.com"
$SMTPserverName = "smtpservername"

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Common")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Common")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client.VersionSpec")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.WorkItemTracking.Client")


$server = new-object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection(New-Object Uri($tfsCollectionUrl))
$buildServer = $server.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])

$fromBuild = $buildServer.QueryBuilds($teamProject, "CPO.Rel") | where { $_.BuildNumber -eq $FromBuildNumber }
$toBuild = $buildServer.QueryBuilds($teamProject, "CPO.Rel") | where { $_.BuildNumber -eq $toBuildNumber }

$versionControlServer = $server.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$workItemStore = $server.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore])
$LinkingService = $server.GetService([Microsoft.TeamFoundation.Client.TswaClientHyperlinkService])

$fromChangesetVersionSpec = New-Object Microsoft.TeamFoundation.VersionControl.Client.ChangesetVersionSpec($fromBuild.SourceGetVersion.Substring(1))
$toChangesetVersionSpec = New-Object Microsoft.TeamFoundation.VersionControl.Client.ChangesetVersionSpec($toBuild.SourceGetVersion.Substring(1))

$recursionType = [Microsoft.TeamFoundation.VersionControl.Client.RecursionType]::Full

$historyBetweenBuilds = $versionControlServer.QueryHistory($versionControlPath, $toChangesetVersionSpec, 0, $recursionType, $null, $fromChangesetVersionSpec, $toChangesetVersionSpec,[Int32]::MaxValue, $true, $false)
$workItemsBetweenBuilds = $historyBetweenBuilds | foreach-object {$_.workitems}

$tabName = "WorkItemTable"

#Create Table object
$WorkItemTable = New-Object system.Data.DataTable $tabName

#Define Columns
$colWorkItemType1 = New-Object system.Data.DataColumn WorkItemType,([string])
$colId = New-Object system.Data.DataColumn Id,([int])
$colTitle = New-Object system.Data.DataColumn Title,([string])
$colState = New-Object system.Data.DataColumn State,([string])
$colAssignedTo = New-Object system.Data.DataColumn AssignedTo,([string])
$colWILink = New-Object system.Data.DataColumn WILink,([string])

#Add the Columns
$WorkItemTable.columns.add($colWorkItemType1)
$WorkItemTable.columns.add($colId)
$WorkItemTable.columns.add($colTitle)
$WorkItemTable.columns.add($colState)
$WorkItemTable.columns.add($colAssignedTo)
$WorkItemTable.columns.add($colWILink)

$workItemsBetweenBuilds |
foreach-object {
if ($_.Type.Name -eq "Task")
{
# Get parent work item of task
foreach($link in $_.WorkItemLinks)
{
if ($link.LinkTypeEnd.Name -eq "Parent")
{
$ParentWorkItem = $workItemStore.GetWorkItem($link.TargetId)

if (($workItemStates -contains $ParentWorkItem.State) -or ($workItemStates -contains "All"))
{
#Create a row
$row = $WorkItemTable.NewRow()

#Enter data in the row
$row.WorkItemType = $ParentWorkItem.Type.Name
$row.Id = $ParentWorkItem.Id
$row.Title = $ParentWorkItem.Title
$row.State = $ParentWorkItem.State
$row.AssignedTo = $ParentWorkItem.Fields["Assigned To"].Value
$row.WILink = $LinkingService.GetArtifactViewerUrl($ParentWorkItem.Uri).AbsoluteUri

#Add the row to the table
$WorkItemTable.Rows.Add($row)
}

break
}
}
}
else
{
# Adding associated work item other than task

if (($workItemStates -contains $_.State) -or ($workItemStates -contains "All"))
{
#Create a row
$row = $WorkItemTable.NewRow()

#Enter data in the row
$row.WorkItemType = $_.Type.Name
$row.Id = $_.Id
$row.Title = $_.Title
$row.State = $_.State
$row.AssignedTo = $_.Fields["Assigned To"].Value
$row.WILink = $LinkingService.GetArtifactViewerUrl($_.Uri).AbsoluteUri

#Add the row to the table
$WorkItemTable.Rows.Add($row)
}
}

}

$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }"
$style = $style + "TD{border: 1px solid black; padding: 5px; }"
$style = $style + "</style>"

#$WorkItemTable |sort WorkItemType,Id -Unique | Select-Object WorkItemType, Id, State, Title, AssignedTo, WILink | ConvertTo-HTML -head $style | Out-File "$PSScriptRoot\tmpBuildNote.txt"

#$messageBody = Get-Content "$PSScriptRoot\tmpBuildNote.txt" | Out-String

$messageBody = $WorkItemTable |sort Id -Unique |sort WorkItemType,State | Select-Object WorkItemType, Id, State, Title, AssignedTo, WILink | ConvertTo-HTML -head $style | Out-String

Send-MailMessage -From $EmailSender -To $Recipients -SmtpServer $SMTPserverName -Body $messageBody -Subject "$toBuildNumber Build Notes from $fromBuildNumber" -BodyAsHtml

With set to get only Resolved state work items, this will send a build note with, User Stories/PBIs, Bugs which are associated with the changesets of the in between builds.


image image


If State is set to All, all state work items are sent.imageimage


Multiple state values can be specified as below.imageimage

No comments: