Created
June 29, 2023 14:28
-
-
Save The-Running-Dev/befd0996bb33e3cdc98af93505291479 to your computer and use it in GitHub Desktop.
TeamCity PowerShell module. Contains various functions for interacting with TeamCity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if ($env:TEAMCITY_VERSION) { | |
# When PowerShell is started through TeamCity's Command Runner, the standard | |
# output will be wrapped at column 80 (a default). This has a negative impact | |
# on service messages, as TeamCity quite naturally fails parsing a wrapped | |
# message. The solution is to set a new, much wider output width. It will | |
# only be set if TEAMCITY_VERSION exists, i.e., if started by TeamCity. | |
$host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size(8192,50) | |
} | |
function TeamCity-Message([string]$text, [string]$status = 'NORMAL', [string]$errorDetails) { | |
$messageAttributes = @{ text=$text; status=$status } | |
if ($errorDetails) { | |
$messageAttributes.errorDetails = $errorDetails | |
} | |
TeamCity-WriteServiceMessage 'message' $messageAttributes | |
} | |
function TeamCity-BlockOpened([string]$name, [string]$description) { | |
$messageAttributes = @{ name=$name } | |
if ($description) { | |
$messageAttributes.description = $description | |
} | |
TeamCity-WriteServiceMessage 'blockOpened' $messageAttributes | |
} | |
function TeamCity-BlockClosed([string]$name) { | |
TeamCity-WriteServiceMessage 'blockClosed' @{ name=$name } | |
} | |
function TeamCity-TestSuiteStarted([string]$name) { | |
TeamCity-WriteServiceMessage 'testSuiteStarted' @{ name=$name } | |
} | |
function TeamCity-TestSuiteFinished([string]$name) { | |
TeamCity-WriteServiceMessage 'testSuiteFinished' @{ name=$name } | |
} | |
function TeamCity-TestStarted([string]$name) { | |
TeamCity-WriteServiceMessage 'testStarted' @{ name=$name } | |
} | |
function TeamCity-TestFinished([string]$name, [int]$duration) { | |
$messageAttributes = @{name=$name; duration=$duration} | |
if ($duration -gt 0) { | |
$messageAttributes.duration=$duration | |
} | |
TeamCity-WriteServiceMessage 'testFinished' $messageAttributes | |
} | |
function TeamCity-TestIgnored([string]$name, [string]$message='') { | |
TeamCity-WriteServiceMessage 'testIgnored' @{ name=$name; message=$message } | |
} | |
function TeamCity-TestOutput([string]$name, [string]$output) { | |
TeamCity-WriteServiceMessage 'testStdOut' @{ name=$name; out=$output } | |
} | |
function TeamCity-TestError([string]$name, [string]$output) { | |
TeamCity-WriteServiceMessage 'testStdErr' @{ name=$name; out=$output } | |
} | |
function TeamCity-TestFailed([string]$name, [string]$message, [string]$details='', [string]$type='', [string]$expected='', [string]$actual='') { | |
$messageAttributes = @{ name=$name; message=$message; details=$details } | |
if (![string]::IsNullOrEmpty($type)) { | |
$messageAttributes.type = $type | |
} | |
if (![string]::IsNullOrEmpty($expected)) { | |
$messageAttributes.expected=$expected | |
} | |
if (![string]::IsNullOrEmpty($actual)) { | |
$messageAttributes.actual=$actual | |
} | |
TeamCity-WriteServiceMessage 'testFailed' $messageAttributes | |
} | |
# See http://confluence.jetbrains.net/display/TCD5/Manually+Configuring+Reporting+Coverage | |
function TeamCity-ConfigureDotNetCoverage([string]$key, [string]$value) { | |
TeamCity-WriteServiceMessage 'dotNetCoverage' @{ $key=$value } | |
} | |
function TeamCity-ImportDotNetCoverageResult([string]$tool, [string]$path) { | |
TeamCity-WriteServiceMessage 'importData' @{ type='dotNetCoverage'; tool=$tool; path=$path } | |
} | |
# See http://confluence.jetbrains.net/display/TCD5/FxCop_#FxCop_-UsingServiceMessages | |
function TeamCity-ImportFxCopResult([string]$path) { | |
TeamCity-WriteServiceMessage 'importData' @{ type='FxCop'; path=$path } | |
} | |
function TeamCity-ImportDuplicatesResult([string]$path) { | |
TeamCity-WriteServiceMessage 'importData' @{ type='DotNetDupFinder'; path=$path } | |
} | |
function TeamCity-ImportInspectionCodeResult([string]$path) { | |
TeamCity-WriteServiceMessage 'importData' @{ type='ReSharperInspectCode'; path=$path } | |
} | |
function TeamCity-ImportNUnitReport([string]$path) { | |
TeamCity-WriteServiceMessage 'importData' @{ type='nunit'; path=$path } | |
} | |
function TeamCity-ImportJSLintReport([string]$path) { | |
TeamCity-WriteServiceMessage 'importData' @{ type='jslint'; path=$path } | |
} | |
function TeamCity-PublishArtifact([string]$path) { | |
TeamCity-WriteServiceMessage 'publishArtifacts' $path | |
} | |
function TeamCity-ReportBuildStart([string]$message) { | |
TeamCity-WriteServiceMessage 'progressStart' $message | |
} | |
function TeamCity-ReportBuildProgress([string]$message) { | |
TeamCity-WriteServiceMessage 'progressMessage' $message | |
} | |
function TeamCity-ReportBuildFinish([string]$message) { | |
TeamCity-WriteServiceMessage 'progressFinish' $message | |
} | |
function TeamCity-ReportBuildStatus([string]$status=$null, [string]$text='') { | |
$messageAttributes = @{ text=$text } | |
if (![string]::IsNullOrEmpty($status)) { | |
$messageAttributes.status=$status | |
} | |
TeamCity-WriteServiceMessage 'buildStatus' $messageAttributes | |
} | |
function TeamCity-ReportBuildProblem([string]$description, [string]$identity=$null) { | |
$messageAttributes = @{ description=$description } | |
if (![string]::IsNullOrEmpty($identity)) { | |
$messageAttributes.identity=$identity | |
} | |
TeamCity-WriteServiceMessage 'buildProblem' $messageAttributes | |
} | |
function TeamCity-SetBuildNumber([string]$buildNumber) { | |
TeamCity-WriteServiceMessage 'buildNumber' $buildNumber | |
} | |
function TeamCity-SetParameter([string]$name, [string]$value) { | |
TeamCity-WriteServiceMessage 'setParameter' @{ name=$name; value=$value } | |
} | |
function TeamCity-SetBuildStatistic([string]$key, [string]$value) { | |
TeamCity-WriteServiceMessage 'buildStatisticValue' @{ key=$key; value=$value } | |
} | |
function TeamCity-EnableServiceMessages() { | |
TeamCity-WriteServiceMessage 'enableServiceMessages' | |
} | |
function TeamCity-DisableServiceMessages() { | |
TeamCity-WriteServiceMessage 'disableServiceMessages' | |
} | |
function TeamCity-CreateInfoDocument([string]$buildNumber='', [boolean]$status=$true, [string[]]$statusText=$null, [System.Collections.IDictionary]$statistics=$null) { | |
$doc=New-Object xml; | |
$buildEl=$doc.CreateElement('build'); | |
if (![string]::IsNullOrEmpty($buildNumber)) { | |
$buildEl.SetAttribute('number', $buildNumber); | |
} | |
$buildEl=$doc.AppendChild($buildEl); | |
$statusEl=$doc.CreateElement('statusInfo'); | |
if ($status) { | |
$statusEl.SetAttribute('status', 'SUCCESS'); | |
} else { | |
$statusEl.SetAttribute('status', 'FAILURE'); | |
} | |
if ($statusText -ne $null) { | |
foreach ($text in $statusText) { | |
$textEl=$doc.CreateElement('text'); | |
$textEl.SetAttribute('action', 'append'); | |
$textEl.set_InnerText($text); | |
$textEl=$statusEl.AppendChild($textEl); | |
} | |
} | |
$statusEl=$buildEl.AppendChild($statusEl); | |
if ($statistics -ne $null) { | |
foreach ($key in $statistics.Keys) { | |
$val=$statistics.$key | |
if ($val -eq $null) { | |
$val='' | |
} | |
$statEl=$doc.CreateElement('statisticsValue'); | |
$statEl.SetAttribute('key', $key); | |
$statEl.SetAttribute('value', $val.ToString()); | |
$statEl=$buildEl.AppendChild($statEl); | |
} | |
} | |
return $doc; | |
} | |
function TeamCity-WriteInfoDocument([xml]$doc) { | |
$dir=(Split-Path $buildFile) | |
$path=(Join-Path $dir 'teamcity-info.xml') | |
$doc.Save($path); | |
} | |
function TeamCity-WriteServiceMessage([string]$messageName, $messageAttributesHashOrSingleValue) { | |
function escape([string]$value) { | |
([char[]] $value | | |
%{ switch ($_) | |
{ | |
"|" { "||" } | |
"'" { "|'" } | |
"`n" { "|n" } | |
"`r" { "|r" } | |
"[" { "|[" } | |
"]" { "|]" } | |
([char] 0x0085) { "|x" } | |
([char] 0x2028) { "|l" } | |
([char] 0x2029) { "|p" } | |
default { $_ } | |
} | |
} ) -join '' | |
} | |
if ($messageAttributesHashOrSingleValue -is [hashtable]) { | |
$messageAttributesString = ($messageAttributesHashOrSingleValue.GetEnumerator() | | |
%{ "{0}='{1}'" -f $_.Key, (escape $_.Value) }) -join ' ' | |
$messageAttributesString = " $messageAttributesString" | |
} elseif ($messageAttributesHashOrSingleValue) { | |
$messageAttributesString = (" '{0}'" -f (escape $messageAttributesHashOrSingleValue)) | |
} | |
Write-Output "##teamcity[$messageName$messageAttributesString]" | |
} | |
# Gets the change log for the specified build ID | |
function TeamCity-GetChangeLog([string] $serverUrl, [string] $username, [string] $password, [int] $buildId){ | |
$changelog = "" | |
# If the build is running inside TeamCity | |
if ($env:TEAMCITY_VERSION) { | |
$buildUrl = "$serverUrl/httpAuth/app/rest/changes?build=id:$($buildId)" | |
$authToken = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($username + ":" + $password)) | |
# Get all the changes | |
$request = [System.Net.WebRequest]::Create($buildUrl) | |
$request.Headers.Add("Authorization", "Basic $authToken"); | |
$xml = [xml](new-object System.IO.StreamReader $request.GetResponse().GetResponseStream()).ReadToEnd() | |
# Get all commit messages for each of them | |
$changelog = Microsoft.PowerShell.Utility\Select-Xml $xml -XPath ` | |
"/changes/change" | Foreach { | |
TeamCity-GetCommitMessage $serverUrl $username $password $_.Node.id | |
} | |
} | |
return $changelog | |
} | |
# Get the commit messages, and files changed for the specified change id | |
# Ignores empty lines, lines containing "#ignore", "merge branch"" or "TeamCity" | |
Function TeamCity-GetCommitMessage([string]$serverUrl, [string]$username, [string]$password, [int]$changeId) | |
{ | |
$getFilesChanged = $false; | |
$request = [System.Net.WebRequest]::Create("$serverUrl/httpAuth/app/rest/changes/id:$changeId") | |
$authToken = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($username + ":" + $password)) | |
$request.Headers.Add("Authorization", "Basic $authToken"); | |
$xml = [xml](new-object System.IO.StreamReader $request.GetResponse().GetResponseStream()).ReadToEnd() | |
Microsoft.PowerShell.Utility\Select-Xml $xml -XPath "/change" | | |
where { ($_.Node["comment"].InnerText.Length -ne 0) ` | |
-and (-Not $_.Node["comment"].InnerText.Contains('#ignore')) ` | |
-and (-Not $_.Node["comment"].InnerText.StartsWith("Merge branch")) ` | |
-and (-Not $_.Node["comment"].InnerText.StartsWith("TeamCity change"))} | | |
foreach { | |
$getFilesChanged = $true | |
$username = (&{If($_.Node["user"] -ne $null) {$_.Node["user"].name.Trim()} Else { $_.Node.Attributes["username"].Value }}) | |
"<br /><strong>$($username + " on " + ([System.DateTime]::ParseExact($_.Node.Attributes["date"].Value, "yyyyMMddTHHmmsszzzz", [System.Globalization.CultureInfo]::InvariantCulture)))</strong><br /><br />" | |
"$($_.Node["comment"].InnerText.Trim().Replace("`n", "`n<br />"))" | |
} | |
if ($getFilesChanged) { | |
"<br /><br /><strong>Files Changed</strong><br /><br />" | |
Microsoft.PowerShell.Utility\Select-Xml $xml -XPath "/change/files" | | |
where { ($_.Node["file"].Length -ne 0)} | | |
foreach { Select-Xml $_.Node -XPath 'file' | | |
foreach { "$($_.Node.Attributes["file"].Value)<br />" } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment