Last active
February 5, 2019 13:39
-
-
Save oceanexplorer/6a91930419b35c1923974af265777a5f to your computer and use it in GitHub Desktop.
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
##----------------------------------------------------------------------- | |
## <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