Skip to content
Snippets Groups Projects
build.cake 10.5 KiB
Newer Older
#tool nuget:?package=NUnit.ConsoleRunner&version=3.10.0
#tool nuget:?package=vswhere&version=2.8.4
#tool nuget:?package=GitVersion.CommandLine&version=5.1.3

#addin nuget:https://api.nuget.org/v3/index.json?package=Cake.Json&version=4.0.0
#addin nuget:https://api.nuget.org/v3/index.json?package=Newtonsoft.Json&version=11.0.2
#addin nuget:https://api.nuget.org/v3/index.json?package=Cake.FileHelpers&version=3.2.1

using System.Net;
using System.Net.Http;

// Commandline arguments
var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
var nugetApiKey = Argument<string>("nugetApiKey", null);
var version = Argument("nugetVersion", "");
var gitlabProjectPath = Argument("gitlabProjectPath", "");
var gitlabProjectId = Argument("gitlabProjectId", "");
var gitlabToken = Argument("gitlabToken", "");

// Define directories
var projects = GetFiles("./**/*.csproj");
var artifactsDir = Directory("./Artifacts");
string nupkgDir;
var solutionFile = GetFiles("./**/*.sln").First();
var projectName = solutionFile.GetFilenameWithoutExtension().ToString();
var nugetSource = "https://api.nuget.org/v3/index.json";
var assemblyInfoSubPath = "Properties/AssemblyInfo.cs";
var semanticVersion = "";
string localNugetFeed;

// get latest MSBuild version
var vsLatest  = VSWhereLatest();	
var msBuildPathX64 = (vsLatest == null) ? null : vsLatest.CombineWithFilePath("./MSBuild/Current/Bin/MSBuild.exe");

Setup(context =>{
	nupkgDir = $"{artifactsDir.ToString()}/nupkg";
	var branch = GitVersion(new GitVersionSettings {
			UpdateAssemblyInfo = false
		}).BranchName.Replace("/", "-");

	localNugetFeed = $"C:\\coscine\\LocalNugetFeeds\\{branch}";
	Information("{0}", branch);
	Information("Started at {0}", DateTime.Now);
});

Teardown(context =>{
	Information("Finished at {0}", DateTime.Now);
});

Task("Clean")
.Description("Cleans all build and artifacts directories")
.Does(() =>{
	var settings = new DeleteDirectorySettings {
		Recursive = true,
		Force = true
	};
	
	var directoriesToClean = new List<DirectoryPath>();
	
	foreach(var project in projects) {
		directoriesToClean.Add(Directory($"{project.GetDirectory()}/obj"));
		directoriesToClean.Add(Directory($"{project.GetDirectory()}/bin"));
	}
	
	directoriesToClean.Add(artifactsDir);

	foreach(var dir in directoriesToClean) {
		Information("Cleaning {0}", dir.ToString());
		if (DirectoryExists(dir)) {
			DeleteDirectory(dir, settings);
			CreateDirectory(dir);
		} else {
			CreateDirectory(dir);
		}
	}
});

Task("Restore")
.Does(() =>{
	NuGetRestore(solutionFile, new NuGetRestoreSettings {
		NoCache = true,
		FallbackSource = new List<string>{ localNugetFeed },
	});
});

Task("Test")
.IsDependentOn("Build")
.Does(() =>{
	NUnit3($"./src/**/bin/{configuration}/*.Tests.dll", new NUnit3Settings {
		// generate the xml file
		NoResults = false,
		Results = new NUnit3Result[] {
			new NUnit3Result() {
				FileName = $"{artifactsDir}/TestResults.xml",
				Transform = $"{Context.Environment.WorkingDirectory}/nunit3-junit.xslt"
			}
		}
	});
});

Task("GitVersion")
.Does(() => {
	if(string.IsNullOrWhiteSpace(version)) {
		version = GitVersion(new GitVersionSettings {
			UpdateAssemblyInfo = false
		}).NuGetVersionV2;
	}
	var index = version.IndexOf("-");
	semanticVersion = index > 0 ? version.Substring(0, index) : version;
	Information("Version: {0}, SemanticVersion: {1}", version, semanticVersion);
});

Task("UpdateAssemblyInfo")
.Does(() =>{
	var index = version.IndexOf("-");
	var semanticVersion = index > 0 ? version.Substring(0, index) : version;

	foreach(var project in projects) {
		CreateAssemblyInfo($"{project.GetDirectory()}/{assemblyInfoSubPath}", new AssemblyInfoSettings {
			Product = project.GetFilenameWithoutExtension().ToString(),
			Title = project.GetFilenameWithoutExtension().ToString(),
			Company = "IT Center, RWTH Aachen University",
			Version = semanticVersion,
			FileVersion = semanticVersion,
			InformationalVersion = version,
			Copyright = $"{DateTime.Now.Year} IT Center, RWTH Aachen University",
			Description = $"{project.GetFilenameWithoutExtension().ToString()} is a part of the CoScInE group."
		});
	}
});

Task("GitlabRelease")
.IsDependentOn("GitVersion")
.Does(() => {
	var client = new HttpClient();
	client.DefaultRequestHeaders.Add("PRIVATE-TOKEN", gitlabToken);
	
	// get the latest tag
	var result = client.GetAsync($"https://git.rwth-aachen.de/api/v4/projects/{gitlabProjectId}/repository/tags").Result;
	if(!result.IsSuccessStatusCode) {
		throw new Exception("Tag query failed.");
	}

	var tagList = result.Content.ReadAsStringAsync().Result;
	var jArray = JArray.Parse(tagList);
	// null if not tags exists yet
	var lastTag = jArray.Select(x => x["name"]).FirstOrDefault();

	var url = $"https://git.rwth-aachen.de/{gitlabProjectPath}";
	
	if(url.EndsWith(".git")) {
		url = url.Substring(0, url.Length - ".git".Length);
	}

	if(url.EndsWith("/")) {
		url = url.Substring(0, url.Length - 1);
	}

	var description = "";
	// First line of description
	// Gitlab compare url, if something can be compared
	if(lastTag == null) {
		description = $"# {semanticVersion} ({DateTime.Now.Year}-{DateTime.Now.Month}-{DateTime.Now.Day})\n\n\n";
	} else {
		description = $"# [{semanticVersion}]({url}/compare/{lastTag}...v{semanticVersion}) ({DateTime.Now.Year}-{DateTime.Now.Month}-{DateTime.Now.Day})\n\n\n";
	}

	// From when will messages be parsed, null results in all messages
	var logParam = "";
	if(lastTag != null) {
		logParam = $"{lastTag}..Head";
	}

	Information(lastTag);

	IEnumerable<string> redirectedStandardOutput;
	var exitCodeWithArgument =
		StartProcess(
			"git",
			new ProcessSettings {
				Arguments = $"log {logParam} --pretty=format:HASH%h:%B",
				RedirectStandardOutput = true
			},
			out redirectedStandardOutput
		);

	var prefixList = new Dictionary<string, List<string>>{
		{"Fix", new List<string>()},
		{"Update", new List<string>()},
		{"New", new List<string>()},
		{"Breaking", new List<string>()},
		{"Docs", new List<string>()},
		{"Build", new List<string>()},
		{"Upgrade", new List<string>()},
		{"Chore", new List<string>()},
	};

	var currentHash = "";
	// Output last line of process output.
	foreach(var line in redirectedStandardOutput) {
		var commitMessage = "";
		if(line.StartsWith("HASH")) {
			currentHash = line.Substring("HASH".Length);
			currentHash = currentHash.Substring(0, currentHash.IndexOf(":"));
			commitMessage = line.Substring(currentHash.Length + line.IndexOf(currentHash) + 1);
		} else {
			commitMessage = line;
		}

		foreach(var kv in prefixList) {
			if(commitMessage.StartsWith($"{kv.Key}:")) {
				kv.Value.Add($"* {commitMessage.Substring(kv.Key.Length + 1).Trim()} {currentHash}");
				break;
			}
		};
	}
	
	foreach(var kv in prefixList) {
		if(kv.Value.Any()) {
			description += $" ### {kv.Key}\n\n";
			foreach(var line in kv.Value) {
				description += $"{line}\n";
			}
			description += "\n";
		}
	}
	// correctly escape the json newlines
	description = description.Replace("\n", "\\n");
	Information("Description: {0}", description);

	// create tag
	result = client.PostAsync($"https://git.rwth-aachen.de/api/v4/projects/{gitlabProjectId}/repository/tags?tag_name=v{semanticVersion}&ref=master", null).Result;
	Information("Create tag: {0}", result.Content.ReadAsStringAsync().Result);
	if(!result.IsSuccessStatusCode) {
		throw new Exception("Tag creation failed.");
	}

	// create release
	var json = $"{{\"name\": \"v{semanticVersion}\", \"tag_name\": \"v{semanticVersion}\", \"description\": \"{description}\"}}";
	var content = new StringContent(json, Encoding.UTF8, "application/json");
	result = client.PostAsync($"https://git.rwth-aachen.de/api/v4/projects/{gitlabProjectId}/releases", content).Result;
	Information("Create release: {0}", result.Content.ReadAsStringAsync().Result);
	if(!result.IsSuccessStatusCode) {
		throw new Exception("Release creation failed.");
	}
});

Task("Build")
.IsDependentOn("Clean")
.IsDependentOn("GitVersion")
.IsDependentOn("UpdateAssemblyInfo")
.IsDependentOn("Restore")
.Does(() =>{
		var frameworkSettingsWindows = new MSBuildSettings {
			Configuration = configuration
		};
		
		frameworkSettingsWindows.ToolPath = msBuildPathX64;
		frameworkSettingsWindows.WorkingDirectory = Context.Environment.WorkingDirectory;

		if (configuration.Equals("Release")) {
			frameworkSettingsWindows.WithProperty("DebugSymbols", "false");
			frameworkSettingsWindows.WithProperty("DebugType", "None");
		}

		// Use MSBuild
		Information("Building {0}", solutionFile);
		MSBuild(solutionFile, frameworkSettingsWindows);
});

Task("NugetPack")
.IsDependentOn("Build")
.Does(() =>{
	foreach(var project in projects) {
			var nuspec = $"{project.GetDirectory()}/{project.GetFilenameWithoutExtension()}.nuspec";
			if(!project.ToString().EndsWith(".Tests") && FileExists(nuspec))
			{
				var settings = new NuGetPackSettings 
				{
					OutputDirectory = nupkgDir,
					Version = version,
					Properties = new Dictionary<string, string>
					{
						{ "Configuration", configuration}
					}
				};				
				NuGetPack(project.ToString(), settings);
			}
		}
});

Task("NugetPush")
.IsDependentOn("NugetPack")
.Does(() =>{
	var nupkgs = GetFiles($"{nupkgDir}/*.nupkg");
	Information("Need to push {0} packages", nupkgs.Count);
	if(!String.IsNullOrWhiteSpace(nugetApiKey)) {
		foreach(var nupkg in nupkgs) {
			Information("Pushing {0}", nupkg);
			NuGetPush(nupkg, new NuGetPushSettings {
				Source = nugetSource,
				ApiKey = nugetApiKey
			});
		}
	} else {
		Information("NugetApiKey is not set. Can't push.");
		throw new Exception("NugetApiKey is not set. Can't push.");
	}
});

Task("CopyToArtifacts")
.Does(() =>{
	foreach(var project in projects) {
		if(!project.GetDirectory().ToString().EndsWith(".Tests")
		&& !FileExists($"{project.GetDirectory()}/{project.GetFilenameWithoutExtension()}.nuspec")
		&& DirectoryExists(project.GetDirectory()))
		{
			Information("Copying {0}/* to {1}", $"{project.GetDirectory()}/bin/{configuration}", artifactsDir);
			CopyDirectory($"{project.GetDirectory()}/bin/{configuration}/", artifactsDir);
		}
	}
});

Task("NugetPushLocal")
.IsDependentOn("NugetPack")
.Does(() =>{	
	var nupkgs = GetFiles($"{nupkgDir}/*.nupkg");
	foreach(var nupkg in nupkgs) {
		if(!DirectoryExists(localNugetFeed)) {
			CreateDirectory(localNugetFeed);
		}
		CopyFile(nupkg.ToString(), $"{localNugetFeed}\\{nupkg.GetFilename()}");
	}
});

Task("Prerelease")
.IsDependentOn("Build")
.IsDependentOn("CopyToArtifacts")
.IsDependentOn("NugetPushLocal");

Task("Release")
.IsDependentOn("NugetPack")
.IsDependentOn("CopyToArtifacts")
.IsDependentOn("NugetPushLocal")
.IsDependentOn("NugetPush");

Task("Default")
.IsDependentOn("Test");

RunTarget(target);