#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);