Skip to content

Instantly share code, notes, and snippets.

@oceanexplorer
Last active February 5, 2019 13:39
Show Gist options
  • Save oceanexplorer/6a91930419b35c1923974af265777a5f to your computer and use it in GitHub Desktop.
Save oceanexplorer/6a91930419b35c1923974af265777a5f to your computer and use it in GitHub Desktop.
##-----------------------------------------------------------------------
## <copyright file="ApplyVersionToAssemblies.ps1">(c) Microsoft Corporation.
## This source is subject to the Microsoft Permissive License.
## See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
## All other rights reserved.</copyright>
##-----------------------------------------------------------------------
# Look for a 0.0.0.0 pattern in the build number.
# If found use it to version the assemblies.
#
# For example, if the 'Build number format' build process parameter
# $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)
# then your build numbers come out like this:
# "Build HelloWorld_2013.07.19.1"
# This script would then apply version 2013.07.19.1 to your assemblies.
function Get-XmlNode([ xml ]$XmlDocument, [string]$NodePath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.')
{
# If a Namespace URI was not given, use the Xml document's default namespace.
if ([string]::IsNullOrEmpty($NamespaceURI))
{
$NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI
}
# In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up.
$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable)
$xmlNsManager.AddNamespace("ns", $NamespaceURI)
$fullyQualifiedNodePath = "/ns:$($NodePath.Replace($($NodeSeparatorCharacter), '/ns:'))"
# Try and get the node, then return it. Returns $null if the node was not found.
$node = $XmlDocument.SelectSingleNode($fullyQualifiedNodePath, $xmlNsManager)
return $node
}
function Get-XmlElementsTextValue([ xml ]$XmlDocument, [string]$ElementPath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.')
{
# Try and get the node.
$node = Get-XmlNode -XmlDocument $XmlDocument -NodePath $ElementPath -NamespaceURI $NamespaceURI -NodeSeparatorCharacter $NodeSeparatorCharacter
# If the node already exists, return its value, otherwise return null.
if ($node)
{
return $node.InnerText
}
else
{
return $null
}
}
function Set-XmlElementsTextValue([ xml ]$XmlDocument, [string]$ElementPath, [string]$TextValue, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.')
{
# Try and get the node.
$node = Get-XmlNode -XmlDocument $XmlDocument -NodePath $ElementPath -NamespaceURI $NamespaceURI -NodeSeparatorCharacter $NodeSeparatorCharacter
# If the node already exists, update its value.
if ($node)
{
$node.InnerText = $TextValue
}
# Else the node doesn't exist yet, so create it with the given value.
else
{
# Create the new element with the given value.
$elementName = $ElementPath.SubString($ElementPath.LastIndexOf($NodeSeparatorCharacter) + 1)
$element = $XmlDocument.CreateElement($elementName, $XmlDocument.DocumentElement.NamespaceURI)
$textNode = $XmlDocument.CreateTextNode($TextValue)
$element.AppendChild($textNode) > $null
# Try and get the parent node.
$parentNodePath = $ElementPath.SubString(0, $ElementPath.LastIndexOf($NodeSeparatorCharacter))
$parentNode = Get-XmlNode -XmlDocument $XmlDocument -NodePath $parentNodePath -NamespaceURI $NamespaceURI -NodeSeparatorCharacter $NodeSeparatorCharacter
if ($parentNode)
{
$parentNode.AppendChild($element) > $null
}
else
{
throw "$parentNodePath does not exist in the xml."
}
}
}
function Set-RequiredBuildVariables
{
# Regular expression pattern to find the version in the build number
# and then apply it to the assemblies
$VersionRegex = "\d+\.\d+\.\d+\.\d+"
$artifactsDirectory = ""
# If this script is not running on a build server, remind user to
# set environment variables so that this script can be debugged
if(-not ($Env:BUILD_SOURCESDIRECTORY -and $Env:BUILD_BUILDNUMBER) -and -not ($Env:AGENT_RELEASEDIRECTORY -and $Env:BUILD_BUILDNUMBER))
{
Write-Error "You must set the following environment variables"
Write-Error "to test this script interactively."
Write-Host '$Env:BUILD_SOURCESDIRECTORY - For example, enter something like:'
Write-Host '$Env:BUILD_SOURCESDIRECTORY = "C:\code\FabrikamTFVC\HelloWorld"'
Write-Host '$Env:BUILD_BUILDNUMBER - For example, enter something like:'
Write-Host '$Env:BUILD_BUILDNUMBER = "Build HelloWorld_0000.00.00.0"'
exit 1
}
if (-not $Env:AGENT_RELEASEDIRECTORY)
{
# Make sure path to source code directory is available
if (-not $Env:BUILD_SOURCESDIRECTORY)
{
Write-Error ("BUILD_SOURCESDIRECTORY environment variable is missing.")
exit 1
}
elseif (-not (Test-Path $Env:BUILD_SOURCESDIRECTORY))
{
Write-Error "BUILD_SOURCESDIRECTORY does not exist: $Env:BUILD_SOURCESDIRECTORY"
exit 1
}
Write-Verbose "BUILD_SOURCESDIRECTORY: $Env:BUILD_SOURCESDIRECTORY"
$artifactsDirectory = $Env:BUILD_SOURCESDIRECTORY
}
else
{
# Make sure path to source code directory is available
if (-not $Env:AGENT_RELEASEDIRECTORY)
{
Write-Error ("AGENT_RELEASEDIRECTORY environment variable is missing.")
exit 1
}
elseif (-not (Test-Path $Env:AGENT_RELEASEDIRECTORY))
{
Write-Error "AGENT_RELEASEDIRECTORY does not exist: $Env:AGENT_RELEASEDIRECTORY"
exit 1
}
Write-Verbose "AGENT_RELEASEDIRECTORY: $Env:AGENT_RELEASEDIRECTORY"
$artifactsDirectory = $Env:AGENT_RELEASEDIRECTORY
}
# Make sure there is a build number
if (-not $Env:BUILD_BUILDNUMBER)
{
Write-Error ("BUILD_BUILDNUMBER environment variable is missing.")
exit 1
}
Write-Verbose "BUILD_BUILDNUMBER: $Env:BUILD_BUILDNUMBER"
# Get and validate the version data
$VersionData = [regex]::matches($Env:BUILD_BUILDNUMBER,$VersionRegex)
switch($VersionData.Count)
{
0
{
Write-Error "Could not find version number data in BUILD_BUILDNUMBER."
exit 1
}
1 {}
default
{
Write-Warning "Found more than instance of version data in BUILD_BUILDNUMBER."
Write-Warning "Will assume first instance is version."
}
}
$script:NewVersion = $VersionData[0]
Write-Verbose "Version: $script:NewVersion"
}
function Set-SemanticVersion {
# check if user wants to use semantic versioning, by including a $suffix parameter. We also check if we are using the SemVer 1.0 or 2.0 format
$script:semanticVersion = ""
if ($suffix -ne "")
{
$vData = [regex]::matches($script:NewVersion, "\d+")
$majorVersion = $vData[0].Value
$minorVersion = $vData[1].Value
$patchVersion = $vData[2].Value
$revision = $vData[3].Value
if ($semVer -eq "1.0")
{
$script:semanticVersion = $majorVersion +"." + $minorVersion + "." + $patchVersion + "-" + $suffix + $revision
}
elseif ($semVer -eq "2.0" -and $isRelease -eq $false)
{
$script:semanticVersion = $majorVersion +"." + $minorVersion + "." + $patchVersion + "-" + $suffix + "." + $revision
}
elseif ($semVer -eq "2.0" -and $isRelease -eq $true)
{
$script:semanticVersion = $majorVersion +"." + $minorVersion + "." + $patchVersion
}
Write-Output "Semantic Version: $script:semanticVersion"
}
else
{
$script:semanticVersion = $script:NewVersion
}
}
function Add-VersionToAssemblyPropertyFiles {
# Apply the version to the assembly property files
$files = gci $artifactsDirectory -recurse -include "*Properties*","My Project" |
?{ $_.PSIsContainer } |
foreach { gci -Path $_.FullName -Recurse -include AssemblyInfo.* }
if($files)
{
Write-Verbose "Will apply $script:NewVersion to $($files.count) files."
foreach ($file in $files) {
$filecontent = Get-Content($file)
attrib $file -r
$filecontent -replace $VersionRegex, $script:NewVersion | Out-File $file
Write-Verbose "$file.FullName - version applied"
}
}
else
{
Write-Warning "Found no *.AssemblyInfo files."
}
}
function Add-VersionToSqlProjectFiles {
# Put the version/description in the DacVersion/DacDescription elements in the .sqlproj (SSDT) project files
$files = gci $artifactsDirectory -recurse |
?{ $_.Extension -eq ".sqlproj" } |
foreach { gci -Path $_.FullName -Recurse -include *.sqlproj }
if($files)
{
Write-Verbose "Will apply $script:NewVersion to $($files.count) files."
foreach ($file in $files) {
[xml]$fileContent = Get-Content($file)
attrib $file -r
# Read in the file contents, update the version element's value, and save the file.
Set-XmlElementsTextValue -XmlDocument $fileContent -ElementPath "Project.PropertyGroup.DacVersion" -TextValue $script:NewVersion
Set-XmlElementsTextValue -XmlDocument $fileContent -ElementPath "Project.PropertyGroup.DacDescription" -TextValue $Env:BUILD_BUILDNUMBER
$fileContent.Save($file)
Write-Verbose "$file.FullName - version applied"
}
}
else
{
Write-Warning "Found no *.sqlproj files."
}
}
function Add-VersionToNuspecFiles {
# Put the version/description in the Version elements in the .nuspec (NuGet) files
$files = gci $artifactsDirectory -recurse |
?{ $_.Extension -eq ".nuspec" } |
foreach { gci -Path $_.FullName -Recurse -include *.nuspec }
if($files)
{
Write-Verbose "Will apply $script:semanticVersion to $($files.count) files."
foreach ($file in $files)
{
[xml]$fileContent = Get-Content($file)
attrib $file -r
# Read in the file contents, update the version element's value, and save the file.
Set-XmlElementsTextValue -XmlDocument $fileContent -ElementPath "package.metadata.version" -TextValue $script:semanticVersion
$fileContent.Save($file)
Write-Verbose "$($file.FullName) - version applied"
}
$env:semanticVersion=$script:semanticVersion
Write-Host "##vso[task.setvariable variable=semanticVersion;]$script:semanticVersion"
}
else
{
Write-Warning "Found no *.nuspec files."
}
}
function Add-VersionToAssemblies {
[CmdletBinding()]
Param(
[string]$suffix="",
[bool] $isRelease = $false,
[ValidateSet("1.0","2.0")][string] $semVer = "2.0",
[string[]] $artifactsToApplyTo = "all"
)
$validArtifacts = "all,assembly,nuspec,sqlproj"
if(-Not $validArtifacts.Contains($artifactsToApplyTo)) {
return Write-Error "The values $artifactsToApplyTo contains an invalid option. Valid options are $validArtifacts"
}
Set-RequiredBuildVariables
Set-SemanticVersion
if($artifactsToApplyTo.Contains("assembly") -or $artifactsToApplyTo.Contains("all")) {
Add-VersionToAssemblyPropertyFiles
}
if($artifactsToApplyTo.Contains("nuspec") -or $artifactsToApplyTo.Contains("all")) {
Add-VersionToNuspecFiles
}
if($artifactsToApplyTo.Contains("sqlproj") -or $artifactsToApplyTo.Contains("all")) {
Add-VersionToSqlProjectFiles
}
}
Export-ModuleMember -Function Add-VersionToAssemblies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment