Created
August 12, 2016 07:53
-
-
Save Antaris/8ad52a96e0f2d9f682d1cd6342c44936 to your computer and use it in GitHub Desktop.
An approach to building .NET Core applications with Cake, XUnit and synchronous `project.json` versionining for both local and on Bamboo
This file contains hidden or 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
#addin "Cake.Powershell" | |
#r "tools/AddIns/Cake.DotNetCoreVersion/Cake.DotNetCoreVersion.dll" | |
////////////////////////////////////////////////////////////////////// | |
// ARGUMENTS | |
////////////////////////////////////////////////////////////////////// | |
var target = Argument("target", "Default"); | |
var configuration = Argument("configuration", "Release"); | |
string version = null; | |
string semanticVersion = null; | |
string prerelease = null; | |
////////////////////////////////////////////////////////////////////// | |
// TASKS | |
////////////////////////////////////////////////////////////////////// | |
Task("Clean") | |
.Does(() => | |
{ | |
CleanDirectory("./artifacts/"); | |
CleanDirectory("./test-results/"); | |
}); | |
Task("Restore") | |
.Does(() => | |
{ | |
DotNetCoreRestore(); | |
}); | |
Task("Version") | |
.Does(() => | |
{ | |
if (Bamboo.IsRunningOnBamboo) | |
{ | |
// MA - We are running a CI build - so need make sure we execute the script with -local = $false | |
StartPowershellFile("./version.ps1", args => | |
{ | |
args.Append("local", "$false"); | |
args.Append("branch", EnvironmentVariable("bamboo_planRepository_branchName")); | |
}); | |
} | |
else | |
{ | |
StartPowershellFile("./version.ps1", args => args.Append("local", "$true")); | |
} | |
string[] lines = System.IO.File.ReadAllLines("./version.props"); | |
foreach (string line in lines) | |
{ | |
if (line.StartsWith("version")) | |
{ | |
version = line.Substring("version=".Length).Trim(); | |
} | |
else if (line.StartsWith("semanticVersion")) | |
{ | |
semanticVersion = line.Substring("semanticVersion=".Length).Trim(); | |
} | |
else if (line.StartsWith("prerelease")) | |
{ | |
prerelease = line.Substring("prerelease=".Length).Trim(); | |
} | |
} | |
Console.WriteLine("Version: {0}", version); | |
Console.WriteLine("SemanticVersion: {0}", semanticVersion); | |
Console.WriteLine("PreRelease: {0}", prerelease); | |
DotNetCoreVersion(new DotNetCoreVersionSettings | |
{ | |
Files = GetFiles("**/project.json"), | |
Version = semanticVersion | |
}); | |
}); | |
Task("Build") | |
.Does(() => | |
{ | |
// MA - Build the libraries | |
DotNetCoreBuild("./src/**/project.json", new DotNetCoreBuildSettings | |
{ | |
Configuration = configuration | |
}); | |
// MA - Build the test libraries | |
DotNetCoreBuild("./tests/**/project.json", new DotNetCoreBuildSettings | |
{ | |
Configuration = configuration | |
}); | |
}); | |
Task("Test") | |
.WithCriteria(() => HasArgument("test")) | |
.Does(() => | |
{ | |
var tests = GetFiles("./tests/**/project.json"); | |
foreach (var test in tests) | |
{ | |
string projectFolder = System.IO.Path.GetDirectoryName(test.FullPath); | |
string projectName = projectFolder.Substring(projectFolder.LastIndexOf('\\') + 1); | |
string resultsFile = "./test-results/" + projectName + ".xml"; | |
DotNetCoreTest(test.FullPath, new DotNetCoreTestSettings | |
{ | |
ArgumentCustomization = args => args.Append("-xml " + resultsFile) | |
}); | |
// MA - Transform the result XML into NUnit-compatible XML for the build server. | |
XmlTransform("./tools/NUnitXml.xslt", "./test-results/" + projectName + ".xml", "./test-results/NUnit." + projectName + ".xml"); | |
} | |
}); | |
Task("Pack") | |
.WithCriteria(() => HasArgument("pack")) | |
.Does(() => | |
{ | |
var projects = GetFiles("./src/**/project.json"); | |
foreach (var project in projects) | |
{ | |
// MA - Pack the libraries | |
DotNetCorePack(project.FullPath, new DotNetCorePackSettings | |
{ | |
Configuration = configuration, | |
OutputDirectory = "./artifacts/" | |
}); | |
} | |
}); | |
////////////////////////////////////////////////////////////////////// | |
// TASK TARGETS | |
////////////////////////////////////////////////////////////////////// | |
Task("Default") | |
.IsDependentOn("Version") | |
.IsDependentOn("Clean") | |
.IsDependentOn("Restore") | |
.IsDependentOn("Build") | |
.IsDependentOn("Test") | |
.IsDependentOn("Pack"); | |
////////////////////////////////////////////////////////////////////// | |
// EXECUTION | |
////////////////////////////////////////////////////////////////////// | |
RunTarget(target); |
This file contains hidden or 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
versionMajor=1 | |
versionMinor=0 | |
versionRev=0 |
This file contains hidden or 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
namespace Cake.DotNetVersion | |
{ | |
using System; | |
using System.Collections.Generic; | |
using Cake.Core; | |
using Cake.Core.Annotations; | |
using Cake.Core.IO; | |
/// <summary> | |
/// Contains functionality required to updating project file versions. | |
/// </summary> | |
[CakeAliasCategory("DotNetCoreVersion")] | |
public static class DotNetCoreVersionExtensions | |
{ | |
[CakeMethodAlias] | |
public static void DotNetCoreVersion(this ICakeContext context, string version) | |
{ | |
var settings = new DotNetCoreVersionSettings | |
{ | |
Files = context.Globber.GetFiles("/**/project.json"), | |
Version = version | |
}; | |
DotNetCoreVersion(context, settings); | |
} | |
[CakeMethodAlias] | |
public static void DotNetCoreVersion(this ICakeContext context, FilePath file, string version) | |
{ | |
var settings = new DotNetCoreVersionSettings | |
{ | |
File = file, | |
Version = version | |
}; | |
DotNetCoreVersion(context, settings); | |
} | |
[CakeMethodAlias] | |
public static void DotNetCoreVersion(this ICakeContext context, IEnumerable<FilePath> files, string version) | |
{ | |
var settings = new DotNetCoreVersionSettings | |
{ | |
Files = files, | |
Version = version | |
}; | |
DotNetCoreVersion(context, settings); | |
} | |
[CakeMethodAlias] | |
public static void DotNetCoreVersion(this ICakeContext context, DotNetCoreVersionSettings settings) | |
{ | |
if (context == null) | |
{ | |
throw new ArgumentNullException(nameof(context)); | |
} | |
if (settings == null) | |
{ | |
throw new ArgumentNullException(nameof(settings)); | |
} | |
if (settings.File == null && settings.Files == null) | |
{ | |
throw new ArgumentException("You must provide a file or set of file paths to process."); | |
} | |
if (string.IsNullOrEmpty(settings.Version)) | |
{ | |
throw new ArgumentException("You must provide a version to set."); | |
} | |
var runner = new DotNetCoreVersionRunner(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); | |
runner.Run(settings); | |
} | |
} | |
} |
This file contains hidden or 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
namespace Cake.DotNetVersion | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using Cake.Core; | |
using Cake.Core.IO; | |
using Cake.Core.Tooling; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
/// <summary> | |
/// Applies a version to a set of project.json files. | |
/// </summary> | |
public class DotNetCoreVersionRunner : Tool<DotNetCoreVersionSettings> | |
{ | |
/// <summary> | |
/// Initialises a new instance of <see cref="DotNetCoreVersionRunner"/> | |
/// </summary> | |
/// <param name="fileSystem">The Cake file system.</param> | |
public DotNetCoreVersionRunner(IFileSystem fileSystem, ICakeEnvironment environment, IProcessRunner processRunner, IToolLocator toolLocator) | |
: base(fileSystem, environment, processRunner, toolLocator) | |
{ | |
} | |
public void Run(DotNetCoreVersionSettings settings) | |
{ | |
if (settings == null) | |
{ | |
throw new ArgumentNullException(nameof(settings)); | |
} | |
if (settings.Files != null) | |
{ | |
foreach (var file in settings.Files) | |
{ | |
RunCore(file, settings.Version); | |
} | |
} | |
else if (settings.File != null) | |
{ | |
RunCore(settings.File, settings.Version); | |
} | |
} | |
protected override IEnumerable<string> GetToolExecutableNames() | |
{ | |
return new string[0]; | |
} | |
protected override string GetToolName() | |
{ | |
return "DotNetCoreVersion"; | |
} | |
private void RunCore(FilePath filePath, string version) | |
{ | |
JObject project; | |
using (var file = new FileStream(filePath.FullPath, FileMode.Open)) | |
using (var stream = new StreamReader(file)) | |
using (var json = new JsonTextReader(stream)) | |
{ | |
project = JObject.Load(json); | |
} | |
var versionAttr = project.Property("version"); | |
if (versionAttr == null) | |
{ | |
project.Add("version", new JValue(version)); | |
} | |
else | |
{ | |
versionAttr.Value = version; | |
} | |
File.WriteAllText(filePath.FullPath, project.ToString(), Encoding.UTF8); | |
} | |
} | |
} |
This file contains hidden or 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
namespace Cake.DotNetVersion | |
{ | |
using System.Collections.Generic; | |
using Cake.Core.IO; | |
using Cake.Core.Tooling; | |
/// <summary> | |
/// Contains settings used by the version tool. | |
/// </summary> | |
public class DotNetCoreVersionSettings : ToolSettings | |
{ | |
/// <summary> | |
/// Gets or sets the collection of project files to update. | |
/// </summary> | |
public IEnumerable<FilePath> Files { get; set; } | |
/// <summary> | |
/// Gets or sets the single file path to update. | |
/// </summary> | |
public FilePath File { get; set; } | |
/// <summary> | |
/// Gets or sets the version to set. | |
/// </summary> | |
public string Version { get; set; } | |
} | |
} |
This file contains hidden or 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
[CmdletBinding()] | |
Param( | |
[bool] $local = $true, | |
[string] $branch = $null | |
) | |
function ReadBuildProps | |
{ | |
$buildProps = ConvertFrom-StringData (Get-Content ./build.props -raw) | |
$buildObject = New-Object PSObject -Property $buildProps | Select-Object versionMajor, versionMinor, versionRev | |
return $buildObject | |
} | |
function ReadBranchName | |
{ | |
$branchName = (& git rev-parse --abbrev-ref HEAD).Trim() | |
return $branchName | |
} | |
function ReadCommitCount | |
{ | |
$count = (& git rev-list --all --count).Trim() | |
return $count | |
} | |
function CreateVersion | |
( | |
[string] $major, | |
[string] $minor, | |
[string] $rev, | |
[string] $branch, | |
[int] $commits, | |
[bool] $local = $true | |
) | |
{ | |
$version = [string]::Concat($major, ".", $minor, ".", $rev) | |
$prerelease = $null | |
$branch = $branch.Replace('/', '-') | |
if ($branch -ne "release") | |
{ | |
if ($local) | |
{ | |
$prerelease = $branch | |
} | |
else | |
{ | |
$prerelease = "$($branch)-$($commits)" | |
} | |
} | |
if ($prerelease -ne $null) | |
{ | |
$semVer = [string]::Concat($version, "-", $prerelease) | |
} | |
else | |
{ | |
$semVer = $version | |
} | |
return @{ | |
Version = $version | |
SemanticVersion = $semVer | |
PreRelease = $prerelease | |
} | |
} | |
function WriteVersion | |
( | |
[string] $version, | |
[string] $semanticVersion, | |
[string] $prerelease | |
) | |
{ | |
Set-Content ./version.props "version=$($version)`nsemanticVersion=$($semanticVersion)`nprerelease=$($prerelease)" | |
} | |
function ResolveVersion | |
( | |
[bool] $local = $true | |
) | |
{ | |
$parts = ReadBuildProps | |
if (!$branch) | |
{ | |
$branch = ReadBranchName | |
} | |
$count = ReadCommitCount | |
$version = CreateVersion -major $parts.versionMajor -minor $parts.versionMinor -rev $parts.versionRev -branch $branch -commits $count -local $local | |
WriteVersion -version $version.Version -semanticVersion $version.SemanticVersion -prerelease $version.PreRelease | |
} | |
ResolveVersion -local $local |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment