Skip to content

Instantly share code, notes, and snippets.

@DamianReeves
Last active November 18, 2016 22:56
Show Gist options
  • Save DamianReeves/16f4690b594850520dd605a28a051aa3 to your computer and use it in GitHub Desktop.
Save DamianReeves/16f4690b594850520dd605a28a051aa3 to your computer and use it in GitHub Desktop.
PS YAML Build
#Requires -Version 4.0
$ErrorActionPreference = 'Stop'
# Ignoring progress stream is vital to keep the performance
# of Invoke-WebRequest decent in Teamcity
$ProgressPreference = 'SilentlyContinue'
function global:RestoreBuildLevelPackages {
# Download paket.exe.
# Use --prefer-nuget to get it from nuget.org first as it is quicker (compressed .nupkg)
$paketVersion = "" # Set this to the value of a specific version of paket.exe to download if need be.
& "$PSScriptRoot\..\.paket\paket.bootstrapper.exe" $paketVersion --prefer-nuget
Push-Location $PsScriptRoot -verbose
try {
& "..\.paket\paket.exe" install
if($LASTEXITCODE -ne 0) {
throw "paket install exited with code $LASTEXITCODE"
}
} finally {
Pop-Location
}
}
<#
.SYNOPSIS
Build <amazing-product>.
.DESCRIPTION
This is really a wrapper around build.ps1 (build.ps1 is our actual build script. E.g.(the script that tells you how to build this crazy thing)
2 main steps:
1 - Restore nuget packages that are needed to get our build engine/tools.
2 - Execute the build. (Invoke-Build build.ps1)
In theory, Teamcity will also use this build command. Probably like this: 'build -Task Build'
.EXAMPLE
build -Task Compile, UnitTests
Run the build script and only execute the 'Compile' and 'UnitTests' tasks.
.EXAMPLE
build
The simplest example! Just execute the build with default values for the -Task parameter.
#>
function global:Build {
[CmdletBinding()]
param(
# The Tasks to execute. '.' means the default task as defined in build.ps1
[string[]] $Task = @('.'),
# The Configuration to build. Either Release or Debug
[ValidateSet('Release', 'Debug')]
[string] $Configuration = 'Release',
# The name of the branch we are building (Set by Teamcity).
# Will be set by Teamcity. Defaults to 'dev' for local developer builds.
[string] $BranchName = 'dev',
# Indicates whether or not BranchName represents the default branch for the source control system currently in use.
# Will be set by Teamcity. Defaults to $false for local developer builds.
[bool] $IsDefaultBranch = $false,
# (Optional) URL to the nuget feed to publish nuget packages to.
# Will be set by Teamcity.
[string] $NugetFeedUrl,
# (Optional) Api Key to the nuget feed to be able to publish nuget packages.
# Will be set by Teamcity.
[string] $NugetFeedApiKey,
# (Optional) Signing service url used to sign dll/exe.
[string] $SigningServiceUrl
)
RestoreBuildLevelPackages
Push-Location $PsScriptRoot -verbose
try
{
# Import the Mohawk.Build module.
Import-Module '.\packages\Mohawk.Build\tools\Mohawk.Build.psm1' -Force -DisableNameChecking
# If building installers you need the Mohawk.Build.Installers module too
#Import-Module ".\packages\Mohawk.Build.Installer\tools\Mohawk.Build.Installer.psm1" -Force -DisableNameChecking
# Call the actual build script
& '.\packages\Invoke-Build\tools\Invoke-Build.ps1' `
-File .\build.ps1 `
-Task $Task `
-BranchName $BranchName `
-IsDefaultBranch $IsDefaultBranch `
-NugetFeedUrl $NugetFeedUrl `
-NugetFeedApiKey $NugetFeedApiKey `
-SigningServiceUrl $SigningServiceUrl `
}
finally
{
Pop-Location
}
}
<#
.SYNOPSIS
Build <amazing-product>.
.DESCRIPTION
This is really a wrapper around build.ps1 (build.ps1 is our actual build script. E.g.(the script that tells you how to build this crazy thing)
2 main steps:
1 - Restore nuget packages that are needed to get our build engine/tools.
2 - Execute the build. (Invoke-Build build.ps1)
In theory, Teamcity will also use this build command. Probably like this: 'build -Task Build'
.EXAMPLE
build -Task Compile, UnitTests
Run the build script and only execute the 'Compile' and 'UnitTests' tasks.
.EXAMPLE
dotnetbuild
The simplest example! Just execute the dotnetbuild with default values for the -Task parameter.
#>
function global:DotNetBuild {
[CmdletBinding()]
param(
# The Tasks to execute. '.' means the default task as defined in build.ps1
[string[]] $Task = @('.'),
# The Configuration to build. Either Release or Debug
[ValidateSet('Release', 'Debug')]
[string] $Configuration = 'Release',
# The name of the branch we are building (Set by Teamcity).
# Will be set by Teamcity. Defaults to 'dev' for local developer builds.
[string] $BranchName = "",
# Indicates whether or not BranchName represents the default branch for the source control system currently in use.
# Will be set by Teamcity. Defaults to $false for local developer builds.
[bool] $IsDefaultBranch = $false,
# (Optional) URL to the nuget feed to publish nuget packages to.
# Will be set by Teamcity.
[string] $NugetFeedUrl,
# (Optional) Api Key to the nuget feed to be able to publish nuget packages.
# Will be set by Teamcity.
[string] $NugetFeedApiKey,
# (Optional) Signing service url used to sign dll/exe.
[string] $SigningServiceUrl
)
RestoreBuildLevelPackages
Push-Location $PsScriptRoot -verbose
try
{
# Import the Mohawk.Build module.
Import-Module '.\packages\Mohawk.Build\tools\Mohawk.Build.psm1' -Force -DisableNameChecking
# If building installers you need the Mohawk.Build.Installers module too
#Import-Module ".\packages\Mohawk.Build.Installer\tools\Mohawk.Build.Installer.psm1" -Force -DisableNameChecking
# Call the actual build script
& '.\packages\Invoke-Build\tools\Invoke-Build.ps1' `
-File .\dotnetbuild.ps1 `
-Task $Task `
-BranchName $BranchName `
-IsDefaultBranch $IsDefaultBranch `
-NugetFeedUrl $NugetFeedUrl `
-NugetFeedApiKey $NugetFeedApiKey `
-SigningServiceUrl $SigningServiceUrl `
}
finally
{
Pop-Location
}
}
$repoName = ([System.IO.DirectoryInfo](Resolve-Path(Join-Path $PSScriptRoot "..")).Path).Name
Write-Host "This is the $repoName repo. And here are the available commands:" -Fore Magenta
Write-Host "`t dotnetbuild" -Fore Green
Write-Host "`t build" -Fore Green
Write-Host "`t installer" -Fore Green
Write-Host "For more info, use help <command-name>" -Fore Magenta
assemblyVersion: 0.1.1.0
semanticVersion: "0.1.1-preview.1+15"
packageVersion: 0.1.1-preview0001
testProjectRegex: "[Tt]ests?$"
branch:
nugetPublishFeeds: ["http://myfeed/ci/feed"]
develop:
nugetPublishFeeds: ["http://myfeed/dev/feed/", "http://myfeed/ci/feed"]
master:
nugetPublishFeeds: ["http://myfeed/dev/feed/", "http://myfeed/ci/feed", "http://myfeed/live/feed"]
projects:
- Project:
Name: Mohawk.Core
PackageVersion: 0.1.1-rc0001
- Project:
Name: Mohawk.Service
IsService: true
- Project:
Name: Mohawk.Tool
IsTool: true
- Project:
Name: Mohawk.Core.Tests
TestSuites: ["xUnit", "NUnit", "MSTest"]
DisablePackaging: true
- Project:
Name: Mohawk.Common.Tests
TestSuites: ["xUnit"]
DisablePackaging: true
IsTestProject: true
[CmdletBinding()]
param(
[string] $Configuration = 'Release',
[string] $BranchName,
[bool] $IsDefaultBranch = $false,
[string] $NugetFeedUrl,
[string] $NugetFeedApiKey,
[string] $SigningServiceUrl
)
$RootDir = "$PsScriptRoot\.." | Resolve-Path
$OutputDir = "$RootDir\.output\$Configuration"
$LogsDir = "$OutputDir\logs"
$NugetPackageOutputDir = "$OutputDir\nugetpackages"
$TestResultsOutputDir = "$OutputDir\testResults"
$BuildStateOutputDir = "$OutputDir\buildState" # A directory used for dynamic build configuration
$SourceProjects = ls (Join-Path $RootDir '.\src\**\project.json') -Recurse
$TestProjects = ls (Join-Path $RootDir '.\test\**\project.json') -Recurse
$AllProjects = ls (Join-Path $RootDir '.\**\project.json') -Recurse
# We probably don't want to publish every single nuget package ever built to our external feed.
# Let's only publish packages built from the default branch (master) by default.
# packages built from non master branches would still be available using the built-in Teamcity feed at
# http://<teamcity-server>/guestAuth/app/nuget/v1/FeedService.svc/
# or http://<teamcity-server>/httpAuth/app/nuget/v1/FeedService.svc/
$PublishNugetPackages = $env:TEAMCITY_VERSION -and $IsDefaultBranch
$NugetExe = "$PSScriptRoot\packages\Nuget.CommandLine\tools\Nuget.exe" | Resolve-Path
# Installer building routines are stored in a separate file
# . $PSScriptRoot\installer.tasks.ps1
task CleanOutputs {
Remove-Item $OutputDir -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
#Remove-Item $LogsDir -Recurse -Force | Out-Null
#Remove-Item $NugetPackageOutputDir -Recurse -Force | Out-Null
}
task CreateFolders {
New-Item $OutputDir -ItemType Directory -Force | Out-Null
New-Item $LogsDir -ItemType Directory -Force | Out-Null
New-Item $NugetPackageOutputDir -ItemType Directory -Force | Out-Null
New-Item $TestResultsOutputDir -ItemType Directory -Force | Out-Null
New-Item $BuildStateOutputDir -ItemType Directory -Force | Out-Null
}
# Synopsis: Retrieve three part version information and release notes from $RootDir\RELEASENOTES.md
# $script:Version = Major.Minor.Build.$VersionSuffix (for installer.tasks)
# $script:AssemblyVersion = $script:Version
# $script:AssemblyFileVersion = $script:Version
# $script:ReleaseNotes = read from RELEASENOTES.md
function GenerateVersionInformationFromReleaseNotesMd([int] $VersionSuffix) {
$ReleaseNotesPath = "$RootDir\RELEASENOTES.md" | Resolve-Path
$Notes = Read-ReleaseNotes -ReleaseNotesPath $ReleaseNotesPath -ThreePartVersion
$script:Version = [System.Version] "$($Notes.Version).$VersionSuffix"
$script:ReleaseNotes = [string] $Notes.Content
# Establish assembly version number
$script:AssemblyVersion = $script:Version
$script:AssemblyFileVersion = $script:Version
#TeamCity-PublishArtifact "$ReleaseNotesPath"
$false
}
# Synopsis: Retrieve two part semantic version information and release notes from $RootDir\RELEASENOTES.md
# $script:Version = Major.Minor.$VersionSuffix
# $script:AssemblyVersion = Major.0.0.0
# $script:AssemblyFileVersion = Major.Minor.$VersionSuffix.0
# $script:ReleaseNotes = read from RELEASENOTES.md
function GenerateSemVerInformationFromReleaseNotesMd([int] $VersionSuffix) {
$ReleaseNotesPath = "$RootDir\RELEASENOTES.md" | Resolve-Path
$Notes = Read-ReleaseNotes -ReleaseNotesPath $ReleaseNotesPath
$script:Version = [System.Version] "$($Notes.Version).$VersionSuffix"
$script:ReleaseNotes = [string] $Notes.Content
# Establish assembly version number
$script:AssemblyVersion = [version] "$($script:Version.Major).0.0.0"
$script:AssemblyFileVersion = [version] "$script:Version.0"
#TeamCity-PublishArtifact "$ReleaseNotesPath"
$false
}
# Synopsis: Retrieve three part version information from .build\version.txt
# $script:Version = Major.Minor.Build.$VersionSuffix
# $script:AssemblyVersion = Major.Minor.Build.$VersionSuffix
# $script:AssemblyFileVersion = Major.Minor.Build.$VersionSuffix
# $script:ReleaseNotes = ''
function GetVersionInformationFromVersionTxt([int] $VersionSuffix) {
$script:Version = [System.Version] "$(Get-Content version.txt).$VersionSuffix"
$script:AssemblyVersion = $script:Version
$script:AssemblyFileVersion = $script:Version
$script:ReleaseNotes = ''
$false
}
# Synopsis: Retrieve three part version information using GitVersion
# $script:Version = NuGetVersion2
# $script:AssemblyVersion = AssemblySemVer
# $script:AssemblyFileVersion = AssemblySemVer
# $script:ReleaseNotes = ''
function GetVersionInformationFromGitVersion([int] $VersionSuffix) {
$GitVersionDir = Join-Path $RootDir ".build\packages\GitVersion.CommandLine\tools\GitVersion.exe"
$Versions = (& $GitVersionDir) | ConvertFrom-Json
$script:Version = ($Versions).NuGetVersionV2
$script:AssemblyVersion = $Versions.AssemblySemVer
$script:AssemblyFileVersion = $Versions.AssemblySemVer
$script:ReleaseNotes = ''
if([System.String]::IsNullOrWhiteSpace($BranchName)) {
$script:BranchName = $Versions.BranchName
}
$true
}
<#
.SYNOPSIS
You can add this to you build script to ensure that psbuild is available before calling
Invoke-MSBuild. If psbuild is not available locally it will be downloaded automatically.
#>
function EnsurePsbuildInstalled{
[cmdletbinding()]
param(
[string]$psbuildInstallUri = 'https://raw.githubusercontent.com/ligershark/psbuild/master/src/GetPSBuild.ps1'
)
process{
if(-not (Get-Command "Invoke-MsBuild" -errorAction SilentlyContinue)){
'Installing psbuild from [{0}]' -f $psbuildInstallUri | Write-Verbose
(new-object Net.WebClient).DownloadString($psbuildInstallUri) | iex
}
else{
'psbuild already loaded, skipping download' | Write-Verbose
}
# make sure it's loaded and throw if not
if(-not (Get-Command "Invoke-MsBuild" -errorAction SilentlyContinue)){
throw ('Unable to install/load psbuild from [{0}]' -f $psbuildInstallUri)
}
}
}
# Ensures the following are set
# $script:Version
# $script:AssemblyVersion
# $script:AssemblyFileVersion
# $script:ReleaseNotes
# $script:NugetPackageVersion = $script:Version or $script:Version-branch
task GenerateVersionInformation {
"Retrieving version information"
# For dev builds, version suffix is always 0
$versionSuffix = 0
if($env:BUILD_NUMBER) {
$versionSuffix = $env:BUILD_NUMBER
}
$versionIsFinal = GetVersionInformationFromGitVersion($versionSuffix)
# GetVersionInformationFromVersionTxt($versionSuffix)
# GenerateVersionInformationFromReleaseNotesMd($versionSuffix)
# GenerateSemVerInformationFromReleaseNotesMd($versionSuffix)
#TeamCity-SetBuildNumber $script:Version
if($versionIsFinal) {
$script:NugetPackageVersion = $script:Version
} else {
$script:NugetPackageVersion = New-NugetPackageVersion -Version $script:Version -BranchName $BranchName -IsDefaultBranch $IsDefaultBranch
}
"Version = $script:Version"
"AssemblyVersion = $script:AssemblyVersion"
"AssemblyFileVersion = $script:AssemblyFileVersion"
"NugetPackageVersion = $script:NugetPackageVersion"
"ReleaseNotes = $script:ReleaseNotes"
}
task GatherBuildConfigurationInfo GenerateVersionInformation, {
if([System.String]::IsNullOrWhiteSpace($NugetFeedUrl)) {
switch -Wildcard ($BranchName) {
"rc" {
$Script:NugetFeedUrl = "https://mohawkgp.pkgs.visualstudio.com/_packaging/rc/nuget/v3/index.json"
}
"rc-*" {
$Script:NugetFeedUrl = "https://mohawkgp.pkgs.visualstudio.com/_packaging/rc/nuget/v3/index.json"
}
"rc/*" {
$Script:NugetFeedUrl = "https://mohawkgp.pkgs.visualstudio.com/_packaging/rc/nuget/v3/index.json"
}
"develop" {
$Script:NugetFeedUrl = "https://mohawkgp.pkgs.visualstudio.com/_packaging/develop/nuget/v3/index.json"
}
"master" {
$Script:NugetFeedUrl = "https://mohawkgp.pkgs.visualstudio.com/_packaging/live/nuget/v3/index.json"
}
default {
$Script:NugetFeedUrl = "https://mohawkgp.pkgs.visualstudio.com/_packaging/CI/nuget/v3/index.json"
}
}
}
}
task WriteBuildConfiguration GatherBuildConfigurationInfo, {
$buildState = @{
"BranchName" = $script:BranchName;
"Version" = $script:Version;
"AssemblyVersion" = $script:AssemblyVersion;
"AssemblyFileVersion" = $script:AssemblyFileVersion;
"NugetPackageVersion" = $script:NugetPackageVersion;
"NugetFeedUrl" = $script:NugetFeedUrl;
"ReleaseNotes" = $script:ReleaseNotes;
}
foreach ($key in $buildState.Keys) {
$variableName = "BuildState_$key"
$theValue = $buildState[$key]
Write-Host "##vso[task.setvariable variable=$variableName;]$theValue"
}
ConvertTo-Json $buildState | Out-File (Join-Path $BuildStateOutputDir "buildState.json")
}
# Synopsis: Update the project.json versions
task UpdateProjectDotJsonVersionInfo {
foreach ($Project in $SourceProjects) {
Set-PackageVersion -path $Project -Version $script:NugetPackageVersion
}
}
# Synopsis: Restore the nuget packages of the Visual Studio solution
task RestorePackages {
exec {& dotnet restore $RootDir }
<#
"Restoring using global.json:"
$globalJsonPath = Join-Path "$RootDir" "global.json" | Resolve-Path -ErrorAction SilentlyContinue
if(Test-Path $globalJsonPath) {
"Restoring packages using global.json:"
exec {& dotnet restore "$RootDir" }
}
#>
<#
"Restoring individual packages for good measure:"
foreach ($Project in $AllProjects) {
"Restoring $Project"
exec {
& dotnet restore $Project
}
}
#>
}
# Synopsis: Update the nuget packages of the Visual Studio solution
task UpdateNugetPackages RestorePackages, {
exec {
& $NugetExe update "$Solution" -Verbosity detailed
}
}
# Synopsis: Update the version info in all AssemblyInfo.cs
task UpdateVersionInfo GenerateVersionInformation, {
"Updating assembly information"
# Ignore anything under the Testing/ folder
@(Get-ChildItem "$RootDir" AssemblyInfo.cs -Recurse) | where { $_.FullName -notlike "$RootDir\Testing\*" } | ForEach {
Update-AssemblyVersion $_.FullName `
-Version $script:AssemblyVersion `
-FileVersion $script:AssemblyFileVersion `
-InformationalVersion $script:NuGetPackageVersion
}
}
# Synopsis: A task that makes sure our initialization tasks have been run before we can do anything useful
task Init CleanOutputs, CreateFolders, RestorePackages, GenerateVersionInformation, WriteBuildConfiguration
# Synopsis: Compile the Visual Studio solution
task Compile Init, UpdateVersionInfo, {
try {
foreach ($Project in $AllProjects) {
exec {
& dotnet build $Project --configuration "$Configuration"
}
}
} finally {
#TeamCity-PublishArtifact "$LogsDir\_msbuild.log.* => logs/msbuild.$Configuration.logs.zip"
}
}
# Synopsis: Execute our unit tests
task UnitTests {
foreach ($Project in $TestProjects) {
$ProjectName = $Project.Directory.Name
$OutputFilename = Join-Path $TestResultsOutputDir "$ProjectName.testResults.xml"
exec {& dotnet test "$Project" -c "$Configuration" -xml $OutputFilename }
}
}
# Synopsis: Build the nuget packages.
task BuildNugetPackages Init, UpdateProjectDotJsonVersionInfo, {
New-Item $NugetPackageOutputDir -ItemType Directory -Force | Out-Null
#$escaped=$ReleaseNotes.Replace('"','\"')
#$properties = "releaseNotes=$escaped"
foreach ($Project in $SourceProjects) {
"Packing $project..."
exec {
& dotnet pack $Project --no-build --output "$NugetPackageOutputDir" --configuration "$Configuration"
}
"Packing for $project completed!"
}
}
# Synopsis: Publish the nuget packages (Teamcity only)
task PublishNugetPackages -If($PublishNugetPackages) {
assert ($NugetFeedUrl) '$NugetFeedUrl is missing. Cannot publish nuget packages'
assert ($NugetFeedApiKey) '$NugetFeedApiKey is missing. Cannot publish nuget packages'
Get-ChildItem $NugetPackageOutputDir -Filter "*.nupkg" | ForEach {
& $NugetExe push $_.FullName -Source $NugetFeedUrl -ApiKey $NugetFeedApiKey
}
}
# Synopsis: Build the project.
task Build Init, Compile, UnitTests, BuildNugetPackages, PublishNugetPackages
# Synopsis: Build the project.
task BuildNoTests Init, Compile, BuildNugetPackages, PublishNugetPackages
# Synopsis: By default, Call the 'Build' task
task . Build
@dfinke
Copy link

dfinke commented Nov 18, 2016

Added :

assembly-version: 0.1.1.0
semantic-version: 0.1.1-preview.1+15
package-version: 0.1.1-preview0001
branch:
    nuget-publish-feeds: ["http://myfeed/ci/feed"]
    -develop:
        nuget-publish-feeds: ["http://myfeed/dev/feed/", "http://myfeed/ci/feed"]
    -master:
        nuget-publish-feeds: ["http://myfeed/dev/feed/", "http://myfeed/ci/feed", "http://myfeed/live/feed"]
projects:
    -Mohawk.Core:    
        package-version: 0.1.1-rc0001
    -Mohawk.Service:
        is-service: true
    -Mohawk.Tool:
        is-tool: true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment