The complete project is available on GitHub, have a look at the repository if the code snippets below don’t make sense in isolation.
What’s in the project?
There are a lot of moving parts here, but in short, this is the setup in Visual Studio:
An api project
The project I want to build is a super simple web api made with dotnet core 2.1. If you clone my repository and run it from Visual Studio, you will get a web site running at https://localhost:44360/api/values.
I started out with the dotnet core web api project template in Visual Studio and removed everything that wasn’t necessary to run it.
A test project
The test project consists of a single xUnit test class, WebTests, with two tests; One that is set up to always succeed and one that always fails.Solution items
In the root directory of the solution you will find the files needed for building. The most important file is build.cake, which defines the build process. To run the Cake script, I also need the Cake dll, so the build.ps1 script is for getting the Cake NuGet package and using it to run build.cake.What is happening in the build process?
To create a build process with Cake, you set up distinct tasks, and set dependencies between them to tell Cake which order to run the tasks. These are the tasks I have defined in build.cake:- Clean
- Empty bin and obj directories
- Test
- Run all xUnit tests in all test projects
- Publish
- Build dll files and move them and static files to a directory ready for deployment
- Pack
- Use OctoPack to put the published files into a zip file with correct version number
- Push
- Send the generated zip file to Octopus Deploy
Setup
This is the beginning of build.cake:
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Diagnostics; #tool "nuget:?package=OctopusTools" var target = Argument("target", "Default"); var build = Argument("build", "0"); var revision = Argument("revision", string.Empty); var octopusUrl = Argument("octopusUrl", string.Empty); var octopusApiKey = Argument("octopusApiKey", string.Empty); var configuration = "Release"; var dotnetcoreVersion = "2.1"; |
Task Clean
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Task("Clean") .WithCriteria(!BuildSystem.IsRunningOnTeamCity) .Does(() => { var dirsToClean = GetDirectories("./**/bin"); dirsToClean.Add(GetDirectories("./**/obj")); foreach(var dir in dirsToClean) { Console.WriteLine(dir); } CleanDirectories(dirsToClean); }); |
Task Test
1 2 3 4 5 6 7 8 |
Task("Test") .IsDependentOn("Clean") .Does(() => { GetFiles("./tests/**/*.csproj") .ToList() .ForEach(file => DotNetCoreTest(file.FullPath)); }); |
Task Publish
1 2 3 4 5 6 7 8 9 10 11 12 |
Task("Publish") .IsDependentOn("Test") .Does(() => { DotNetCorePublish(".", new DotNetCorePublishSettings { Configuration = configuration, EnvironmentVariables = new Dictionary<string, string> { { "build", build }, { "revision", revision } } }); }); |
1 2 3 4 5 6 7 |
<PropertyGroup> <TargetFramework>netcoreapp2.1</TargetFramework> <Version>1.2.3</Version> <Version Condition=" '$(Build)' != '' ">$(Version).$(Build)</Version> <InformationalVersion>$(Version)</InformationalVersion> <InformationalVersion Condition=" '$(Revision)' != '' ">$(InformationalVersion)-g$(Revision)</InformationalVersion> </PropertyGroup> |
Risk • History of recent MI or- upper range (vigorous activity) viagra online.
Task Pack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Task("Pack") .IsDependentOn("Publish") .Does(() => { var projectName = "Web"; var basePath = $"./src/{projectName}/bin/{configuration}/netcoreapp{dotnetcoreVersion}/publish"; var version = FileVersionInfo.GetVersionInfo($"{basePath}/{projectName}.dll").FileVersion; OctoPack($"CakeXunitDemo.{projectName}", new OctopusPackSettings { BasePath = basePath, Format = OctopusPackFormat.Zip, Version = version, OutFolder = new DirectoryPath(".") }); }); |
Task OctoPush
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Task("OctoPush") .IsDependentOn("Pack") .WithCriteria(BuildSystem.IsRunningOnTeamCity) .WithCriteria(!string.IsNullOrEmpty(octopusUrl)) .WithCriteria(!string.IsNullOrEmpty(octopusApiKey)) .Does(() => { var packagePathCollection = new FilePathCollection( System.IO.Directory.GetFiles(".", "CakeXunitDemo.*.zip").Select(filePath => new FilePath(filePath)), new PathComparer(false)); OctoPush( octopusUrl, octopusApiKey, packagePathCollection, new OctopusPushSettings { ReplaceExisting = true } ); }); |
Task Default and method RunTarget()
1 2 3 4 |
Task("Default") .IsDependentOn("OctoPush"); RunTarget(target); |
Build.ps1
To actually run the Cake script, you need the Cake NuGet package. You can download it manually, but instead of doing that, I download it and run the Cake script using a PowerShell script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[CmdletBinding()] Param( [string]$target = "Default", [string]$build = "0", [string]$revision = "", [string]$octopusUrl = "", [string]$octopusApiKey = "") If (Test-Path tools) { Remove-Item tools -Force -Recurse } mkdir tools '<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>netcoreapp2.1</TargetFramework></PropertyGroup></Project>' > tools\build.csproj dotnet add tools/build.csproj package Cake.CoreCLR --package-directory tools $pathToCakeDll = (Get-Item tools/cake.coreclr/*/Cake.dll).FullName dotnet $pathToCakeDll build.cake -target="$target" -build="$build" -revision="$revision" -octopusUrl="$octopusUrl" -octopusApiKey="$octopusApiKey" |
Set up TeamCity to run build.ps1
In TeamCity, I have a project that automatically fetches new commits from a GitHub repository. The project contains a single build step, a PowerShell runner, with these settings: Runner type: PowerShell Format stderr output as: error Script: Source code Script execution mode: Execute .ps1 from external file Script source:
1 2 |
.\build.ps1 -target Default -build %build.counter% -revision %build.vcs.number% -octopusUrl %OctopusUrl% -octopusApiKey %OctopusApiKey% exit $LASTEXITCODE |
Display test results in TeamCity
Out of the box, TeamCity will run the xUnit tests, and will stop the build process if one of the tests fail. But you will only get a generic error message. To get a detailed view of which tests have passed and which have failed under the Tests tab in TeamCity, you need to install NuGet package TeamCity.VSTest.TestAdapter in the test project.