public Build() { Cake.Log.Verbosity = Verbosity.Diagnostic; const string solutionName = "CodeCake"; const string solutionFileName = solutionName + ".sln"; var releasesDir = Cake.Directory("CodeCakeBuilder/Releases"); Cake.CreateDirectory(releasesDir); var projects = Cake.ParseSolution(solutionFileName) .Projects .Where(p => !(p is SolutionFolder) && p.Name != "CodeCakeBuilder"); // We do not publish .Tests projects for this solution. var projectsToPublish = projects.Where(p => !p.Path.Segments.Contains("Tests")); // The SimpleRepositoryInfo should be computed once and only once. SimpleRepositoryInfo gitInfo = Cake.GetSimpleRepositoryInfo(); // This default global info will be replaced by Check-Repository task. // It is allocated here to ease debugging and/or manual work on complex build script. CheckRepositoryInfo globalInfo = new CheckRepositoryInfo { Version = gitInfo.SafeNuGetVersion }; Setup(context => { context.Information("Executed BEFORE the first task."); }); Teardown(context => { context.Information("Executed AFTER the last task."); }); TaskSetup(setupContext => { setupContext.Information($"TaskSetup for Task: {setupContext.Task.Name}"); }); TaskTeardown(teardownContext => { teardownContext.Information($"TaskTeardown for Task: {teardownContext.Task.Name}"); }); Task("Check-Repository") .Does(() => { globalInfo = StandardCheckRepository(projectsToPublish, gitInfo); if (globalInfo.ShouldStop) { Cake.TerminateWithSuccess("All packages from this commit are already available. Build skipped."); } }); Task("Clean") .Does(() => { Cake.CleanDirectories(projects.Select(p => p.Path.GetDirectory().Combine("bin"))); Cake.CleanDirectories(releasesDir); }); // Use N as the first answser: this test takes a looong time (why?) // In -autointeraction mode, this will be skipped (unless explicitly asked from the command line). Task("AutoTests") .WithCriteria(() => Cake.InteractiveMode() == InteractiveMode.NoInteraction || Cake.ReadInteractiveOption("RunAutoTests", "Run Auto Tests (for Dynamic paths)?", 'N', 'Y') == 'Y') .Does(() => { void ShouldFindAutoTestFolderFromDynamicPaths(bool shouldFind) { string[] paths = Cake.Environment.GetEnvironmentVariable("PATH").Split(new char[] { Cake.Environment.Platform.IsUnix() ? ':' : ';' }, StringSplitOptions.RemoveEmptyEntries); // Cake does not normalize the paths to System.IO.Path.DirectorySeparatorChar. We do it here. string af = Cake.Environment.WorkingDirectory.FullPath + "/CodeCakeBuilder/AutoTests".Replace('\\', '/'); bool autoFolder = paths.Select(p => p.Replace('\\', '/')).Contains(af); if (autoFolder != shouldFind) { throw new Exception(shouldFind ? "AutoTests folder should be found." : "AutoTests folder should not be found."); } } void ShouldFindTestTxtFileFromDynamicPaths(bool shouldFind) { string[] paths = Cake.Environment.GetEnvironmentVariable("PATH").Split(new char[] { Cake.Environment.Platform.IsUnix() ? ':' : ';' }, StringSplitOptions.RemoveEmptyEntries); bool findTestTxtFileInPath = paths.Select(p => System.IO.Path.Combine(p, "Test.txt")).Any(f => System.IO.File.Exists(f)); if (findTestTxtFileInPath != shouldFind) { throw new Exception(shouldFind ? "Should find Text.txt file." : "Should not find Test.txt file."); } } if (System.IO.Directory.Exists("CodeCakeBuilder/AutoTests")) { Cake.DeleteDirectory("CodeCakeBuilder/AutoTests", new DeleteDirectorySettings() { Recursive = true, Force = true }); } ShouldFindAutoTestFolderFromDynamicPaths(false); ShouldFindTestTxtFileFromDynamicPaths(false); Cake.CreateDirectory("CodeCakeBuilder/AutoTests/TestDynamic0"); ShouldFindAutoTestFolderFromDynamicPaths(true); ShouldFindTestTxtFileFromDynamicPaths(false); System.IO.File.WriteAllText("CodeCakeBuilder/AutoTests/TestDynamic0/Test.txt", "c"); ShouldFindAutoTestFolderFromDynamicPaths(true); ShouldFindTestTxtFileFromDynamicPaths(true); Cake.DeleteDirectory("CodeCakeBuilder/AutoTests/TestDynamic0", new DeleteDirectorySettings() { Recursive = true, Force = true }); Cake.CreateDirectory("CodeCakeBuilder/AutoTests/Sub/TestDynamicB"); ShouldFindAutoTestFolderFromDynamicPaths(true); ShouldFindTestTxtFileFromDynamicPaths(false); System.IO.File.WriteAllText("CodeCakeBuilder/AutoTests/Sub/TestDynamicB/Test.txt", "c"); ShouldFindTestTxtFileFromDynamicPaths(true); Cake.DeleteDirectory("CodeCakeBuilder/AutoTests", new DeleteDirectorySettings() { Recursive = true, Force = true }); ShouldFindTestTxtFileFromDynamicPaths(false); ShouldFindAutoTestFolderFromDynamicPaths(false); }); Task("Build") .IsDependentOn("Clean") .IsDependentOn("Check-Repository") .IsDependentOn("AutoTests") .Does(() => { StandardSolutionBuild(solutionFileName, gitInfo, globalInfo.BuildConfiguration); }); Task("Create-NuGet-Packages") .WithCriteria(() => gitInfo.IsValid) .IsDependentOn("Build") .Does(() => { StandardCreateNuGetPackages(releasesDir, projectsToPublish, gitInfo, globalInfo.BuildConfiguration); }); Task("Push-NuGet-Packages") .IsDependentOn("Create-NuGet-Packages") .WithCriteria(() => gitInfo.IsValid) .Does(() => { StandardPushNuGetPackages(globalInfo, releasesDir); }); Task("Default").IsDependentOn("Push-NuGet-Packages"); }
public Build() { const string solutionName = "CK-Core"; const string solutionFileName = solutionName + ".sln"; var releasesDir = Cake.Directory("CodeCakeBuilder/Releases"); SimpleRepositoryInfo gitInfo = null; // Configuration is either "Debug" or "Release". string configuration = null; // We do not publish .Tests projects for this solution. var projectsToPublish = Cake.ParseSolution(solutionFileName) .Projects .Where(p => p.Name != "CodeCakeBuilder" && !p.Path.Segments.Contains("Tests")); Task("Check-Repository") .Does(() => { gitInfo = Cake.GetSimpleRepositoryInfo(); if (!gitInfo.IsValid) { if (Cake.IsInteractiveMode() && Cake.ReadInteractiveOption("Repository is not ready to be published. Proceed anyway?", 'Y', 'N') == 'Y') { Cake.Warning("GitInfo is not valid, but you choose to continue..."); } else { throw new Exception("Repository is not ready to be published."); } } configuration = gitInfo.IsValidRelease && gitInfo.PreReleaseName.Length == 0 ? "Release" : "Debug"; Cake.Information("Publishing {0} projects with version={1} and configuration={2}: {3}", projectsToPublish.Count(), gitInfo.SemVer, configuration, projectsToPublish.Select(p => p.Name).Concatenate()); }); Task("Restore-NuGet-Packages") .Does(() => { Cake.NuGetRestore(solutionFileName); }); Task("Clean") .IsDependentOn("Check-Repository") .Does(() => { Cake.CleanDirectories("**/bin/" + configuration, d => !d.Path.Segments.Contains("CodeCakeBuilder")); Cake.CleanDirectories("**/obj/" + configuration, d => !d.Path.Segments.Contains("CodeCakeBuilder")); Cake.CleanDirectories(releasesDir); Cake.DeleteFiles("Tests/**/TestResult.xml"); }); Task("Build") .IsDependentOn("Clean") .IsDependentOn("Restore-NuGet-Packages") .IsDependentOn("Check-Repository") .Does(() => { using (var tempSln = Cake.CreateTemporarySolutionFile(solutionFileName)) { tempSln.ExcludeProjectsFromBuild("CodeCakeBuilder"); Cake.MSBuild(tempSln.FullPath, settings => { settings.Configuration = configuration; settings.Verbosity = Verbosity.Minimal; // Always generates Xml documentation. Relies on this definition in the csproj files: // // <PropertyGroup Condition=" $(GenerateDocumentation) != '' "> // <DocumentationFile>bin\$(Configuration)\$(AssemblyName).xml</DocumentationFile> // </PropertyGroup> // settings.Properties.Add("GenerateDocumentation", new[] { "true" }); }); } }); Task("Unit-Testing") .IsDependentOn("Build") .Does(() => { Cake.CreateDirectory(releasesDir); var testDlls = Cake.ParseSolution(solutionFileName) .Projects .Where(p => p.Name.EndsWith(".Tests")) .Select(p => p.Path.GetDirectory().CombineWithFilePath("bin/" + configuration + "/" + p.Name + ".dll")); Cake.Information("Testing: {0}", string.Join(", ", testDlls.Select(p => p.GetFilename().ToString()))); Cake.NUnit(testDlls, new NUnitSettings() { Framework = "v4.5", OutputFile = releasesDir.Path + "/TestResult.txt" }); }); Task("Create-NuGet-Packages") .IsDependentOn("Unit-Testing") .WithCriteria(() => gitInfo.IsValid) .Does(() => { Cake.CreateDirectory(releasesDir); var settings = new NuGetPackSettings() { Version = gitInfo.NuGetVersion, BasePath = Cake.Environment.WorkingDirectory, OutputDirectory = releasesDir }; Cake.CopyFiles("CodeCakeBuilder/NuSpec/*.nuspec", releasesDir); foreach (var nuspec in Cake.GetFiles(releasesDir.Path + "/*.nuspec")) { TransformText(nuspec, configuration, gitInfo); Cake.NuGetPack(nuspec, settings); } Cake.DeleteFiles(releasesDir.Path + "/*.nuspec"); }); Task("Push-NuGet-Packages") .IsDependentOn("Create-NuGet-Packages") .WithCriteria(() => gitInfo.IsValid) .Does(() => { IEnumerable <FilePath> nugetPackages = Cake.GetFiles(releasesDir.Path + "/*.nupkg"); if (Cake.IsInteractiveMode()) { var localFeed = Cake.FindDirectoryAbove("LocalFeed"); if (localFeed != null) { Cake.Information("LocalFeed directory found: {0}", localFeed); if (Cake.ReadInteractiveOption("Do you want to publish to LocalFeed?", 'Y', 'N') == 'Y') { Cake.CopyFiles(nugetPackages, localFeed); } } } if (gitInfo.IsValidRelease) { if (gitInfo.PreReleaseName == "" || gitInfo.PreReleaseName == "prerelease" || gitInfo.PreReleaseName == "rc") { PushNuGetPackages("NUGET_API_KEY", "https://www.nuget.org/api/v2/package", nugetPackages); } else { // An alpha, beta, delta, epsilon, gamma, kappa goes to invenietis-preview. PushNuGetPackages("MYGET_PREVIEW_API_KEY", "https://www.myget.org/F/invenietis-preview/api/v2/package", nugetPackages); } } else { Debug.Assert(gitInfo.IsValidCIBuild); PushNuGetPackages("MYGET_CI_API_KEY", "https://www.myget.org/F/invenietis-ci/api/v2/package", nugetPackages); } }); Task("Build-DocFX") .IsDependentOn("Check-Repository") .WithCriteria(() => gitInfo.IsValid) .Does(() => { var settingsFile = Cake.File("DocFX/docfx.json"); var settingsFileCopy = Cake.File("DocFX/docfx.json.old"); try { // Create a copy restored in finally{} Cake.Information($"Backing up {settingsFile} to {settingsFileCopy}"); Cake.CopyFile(settingsFile, settingsFileCopy); // Edit the settings file // TODO: A proper visitor & rewriter; target properties are: // o.build.globalMetadata._appVersion // o.build.globalMetadata._appShortVersion Cake.Information($"Writing {settingsFile}"); Cake.Information($"* _appVersion: {gitInfo.SemVer}"); Cake.Information($"* _appShortVersion: {gitInfo.NuGetVersion}"); File.WriteAllText( settingsFile, File.ReadAllText(settingsFile) .Replace("%%VERSION%%", gitInfo.SemVer) .Replace("%%SHORTVERSION%%", gitInfo.NuGetVersion) ); // Build DocFX project var docFxProjectFile = Cake.File("DocFX/DocFX.csproj"); Cake.Information($"Building {docFxProjectFile}"); Cake.MSBuild(docFxProjectFile, settings => { settings.Configuration = configuration; settings.Verbosity = Verbosity.Minimal; }); // Pack output var outDir = Cake.Directory("DocFX/_site"); // Configured in DocFX/docfx.json var outZip = releasesDir.Path.CombineWithFilePath($@"{solutionName}.{gitInfo.SemVer}.DocFX.zip"); Cake.Information($"Packing {outDir} to {outZip}"); Cake.Zip(outDir, outZip); } finally { // Delete existing file and restore file copy if (Cake.FileExists(settingsFileCopy)) { Cake.Information($"Restoring {settingsFile}"); if (Cake.FileExists(settingsFile)) { Cake.DeleteFile(settingsFile); } Cake.MoveFile(settingsFileCopy, settingsFile); } } }); // The Default task for this script can be set here. Task("Default") .IsDependentOn("Push-NuGet-Packages"); }
public Build() { const string solutionName = "Yodii-Script"; const string solutionFileName = solutionName + ".sln"; var releasesDir = Cake.Directory("CodeCakeBuilder/Releases"); var projects = Cake.ParseSolution(solutionFileName) .Projects .Where(p => !(p is SolutionFolder) && p.Name != "CodeCakeBuilder"); // We do not publish .Tests projects for this solution. var projectsToPublish = projects .Where(p => !p.Path.Segments.Contains("Tests")); // The SimpleRepositoryInfo should be computed once and only once. SimpleRepositoryInfo gitInfo = Cake.GetSimpleRepositoryInfo(); // This default global info will be replaced by Check-Repository task. // It is allocated here to ease debugging and/or manual work on complex build script. CheckRepositoryInfo globalInfo = new CheckRepositoryInfo(gitInfo, projectsToPublish); Task("Check-Repository") .Does(() => { globalInfo = StandardCheckRepository(projectsToPublish, gitInfo); if (globalInfo.ShouldStop) { Cake.TerminateWithSuccess("All packages from this commit are already available. Build skipped."); } }); Task("Clean") .Does(() => { Cake.CleanDirectories(projects.Select(p => p.Path.GetDirectory().Combine("bin"))); Cake.CleanDirectories(releasesDir); }); Task("Build") .IsDependentOn("Clean") .IsDependentOn("Check-Repository") .Does(() => { StandardSolutionBuild(solutionFileName, gitInfo, globalInfo.BuildConfiguration); }); Task("Unit-Testing") .IsDependentOn("Build") .WithCriteria(() => Cake.InteractiveMode() == InteractiveMode.NoInteraction || Cake.ReadInteractiveOption("RunUnitTests", "Run Unit Tests?", 'Y', 'N') == 'Y') .Does(() => { StandardUnitTests(globalInfo, projects.Where(p => p.Name.EndsWith(".Tests"))); }); Task("Create-NuGet-Packages") .WithCriteria(() => gitInfo.IsValid) .IsDependentOn("Unit-Testing") .Does(() => { StandardCreateNuGetPackages(releasesDir, projectsToPublish, gitInfo, globalInfo.BuildConfiguration); }); Task("Push-NuGet-Packages") .IsDependentOn("Create-NuGet-Packages") .WithCriteria(() => gitInfo.IsValid) .Does(() => { StandardPushNuGetPackages(globalInfo, releasesDir); }); // The Default task for this script can be set here. Task("Default") .IsDependentOn("Push-NuGet-Packages"); }
public Build() { Cake.Log.Verbosity = Verbosity.Diagnostic; const string solutionName = "CK-DB"; const string solutionFileName = solutionName + ".sln"; const string integrationSolution = "IntegrationTests/IntegrationTests.sln"; const string integrationTestsDirectory = "IntegrationTests/Tests/AllPackages.Tests"; const string integrationTestsCSProj = integrationTestsDirectory + "/AllPackages.Tests.csproj"; var releasesDir = Cake.Directory("CodeCakeBuilder/Releases"); var projects = Cake.ParseSolution(solutionFileName) .Projects .Where(p => !(p is SolutionFolder) && !p.Path.Segments.Contains("IntegrationTests") && p.Name != "CodeCakeBuilder"); var integrationProjects = Cake.ParseSolution(integrationSolution) .Projects .Where(p => !(p is SolutionFolder)); // We publish .Tests projects for this solution. var projectsToPublish = projects; // The SimpleRepositoryInfo should be computed once and only once. SimpleRepositoryInfo gitInfo = Cake.GetSimpleRepositoryInfo(); // This default global info will be replaced by Check-Repository task. // It is allocated here to ease debugging and/or manual work on complex build script. CheckRepositoryInfo globalInfo = new CheckRepositoryInfo { Version = gitInfo.SafeNuGetVersion }; var vCKDatabase = XDocument.Load("Common/DependencyVersions.props") .Root .Elements("PropertyGroup") .Elements("CKDatabaseVersion") .Single() .Value; Cake.Information($"Using CK-Database version {vCKDatabase}."); string ckSetupNet461Path = System.IO.Path.GetFullPath(System.IO.Path.Combine(releasesDir, "CKSetup-Net461")); Task("Check-Repository") .Does(() => { globalInfo = StandardCheckRepository(projectsToPublish, gitInfo); if (globalInfo.ShouldStop) { Cake.TerminateWithSuccess("All packages from this commit are already available. Build skipped."); } }); Task("Clean") .Does(() => { Cake.CleanDirectories(projects.Select(p => p.Path.GetDirectory().Combine("bin"))); Cake.CleanDirectories(releasesDir); Cake.DeleteFiles("Tests/**/TestResult*.xml"); }); Task("Build") .IsDependentOn("Check-Repository") .IsDependentOn("Clean") .Does(() => { StandardSolutionBuild(solutionFileName, gitInfo, globalInfo.BuildConfiguration); }); Task("Unit-Testing") .IsDependentOn("Build") .WithCriteria(() => Cake.InteractiveMode() == InteractiveMode.NoInteraction || Cake.ReadInteractiveOption("RunUnitTests", "Run Unit Tests?", 'Y', 'N') == 'Y') .Does(() => { var testProjects = projects.Where(p => p.Name.EndsWith(".Tests")); StandardUnitTests(globalInfo.BuildConfiguration, testProjects); }); Task("Create-NuGet-Packages") .IsDependentOn("Unit-Testing") .Does(() => { StandardCreateNuGetPackages(releasesDir, projectsToPublish, gitInfo, globalInfo.BuildConfiguration); }); Task("Compile-IntegrationTests") .IsDependentOn("Create-NuGet-Packages") .Does(() => { //if( !gitInfo.IsValid ) //{ // string nugetV3Cache = Environment.ExpandEnvironmentVariables( @"%USERPROFILE%/.nuget/packages" ); // Cake.CleanDirectories( nugetV3Cache + @"/**/" + CSemVer.SVersion.ZeroVersion ); //} //string version = gitInfo.IsValid // ? gitInfo.SafeNuGetVersion // : CSemVer.SVersion.ZeroVersion.ToString(); //Cake.DotNetCoreBuild( integrationSolution, new DotNetCoreBuildSettings() //{ // ArgumentCustomization = c => c.Append( $@"/p:CKDBVersion=""{version}""" ) //} ); //Cake.DotNetCorePublish( integrationTestsCSProj, new DotNetCorePublishSettings() //{ // ArgumentCustomization = c => c.Append( $@"/p:CKDBVersion=""{version}""" ).Append( " /p:IsPackable=true" ), // Framework = "netcoreapp2.0" //} ); }); Task("Download-CKSetup-Net461-From-Store-and-Unzip-it") .Does(() => { //var tempFile = Cake.DownloadFile( "http://cksetup.invenietis.net/dl-zip/CKSetup/Net461" ); //Cake.Unzip( tempFile, ckSetupNet461Path ); }); Task("Run-CKSetup-On-IntegrationTests-AllPackages-Net461-With-CKSetup-Net461") .IsDependentOn("Compile-IntegrationTests") .IsDependentOn("Download-CKSetup-Net461-From-Store-and-Unzip-it") .Does(() => { //var binPath = System.IO.Path.GetFullPath( integrationTestsDirectory + $"/bin/{globalInfo.BuildConfiguration}/net461" ); //string dbCon = GetConnectionStringForIntegrationTestsAllPackages(); //string configFile = System.IO.Path.Combine( releasesDir, "CKSetup-IntegrationTests-AllPackages-Net461.xml" ); //Cake.TransformTextFile( "CodeCakeBuilder/CKSetup-IntegrationTests-AllPackages.xml", "{", "}" ) // .WithToken( "binPath", binPath ) // .WithToken( "connectionString", dbCon ) // .Save( configFile ); //var cmdLine = $@"{ckSetupNet461Path}\CKSetup.exe run ""{configFile}"" -v Monitor "; //if( globalInfo.LocalFeedPath != null && globalInfo.LocalFeedPath.EndsWith( "LocalFeed\\Blank" ) ) //{ // cmdLine += $"--store \"{System.IO.Path.Combine( globalInfo.LocalFeedPath, "CKSetupStore" )}\""; //} //int result = Cake.RunCmd( cmdLine ); //if( result != 0 ) throw new Exception( "CKSetup.exe failed." ); }); Task("Run-IntegrationTests") .IsDependentOn("Compile-IntegrationTests") .WithCriteria(() => Cake.InteractiveMode() == InteractiveMode.NoInteraction || Cake.ReadInteractiveOption("Run integration tests?", 'Y', 'N') == 'Y') .Does(() => { // There should be a bad database test name here. // Skip it for now... // // Running AllPackages.Tests executes a CKSetup on MultiBinPaths with the // 3 applications (FacadeApp) on the CKDB_TEST_MultiBinPaths database. // The task "Run-Facade-App-Tests" below executes the 3 tests apps which // use the burned connection string of the generated StObjMap. // //var integrationTests = integrationProjects.Where( p => p.Name == "AllPackages.Tests" ); //var testDlls = integrationTests // .Select( p => System.IO.Path.Combine( // p.Path.GetDirectory().ToString(), "bin", globalInfo.BuildConfiguration, "net461", p.Name + ".dll" ) ); //Cake.Information( $"Testing: {string.Join( ", ", testDlls )}" ); //Cake.NUnit( testDlls, new NUnitSettings() { Framework = "v4.5" } ); }); Task("Run-Facade-App-Tests") .IsDependentOn("Run-IntegrationTests") .WithCriteria(() => Cake.InteractiveMode() == InteractiveMode.NoInteraction || Cake.ReadInteractiveOption("Run Facade application tests?", 'Y', 'N') == 'Y') .Does(() => { //var facadeTests = integrationProjects.Where( p => p.Name.StartsWith( "FacadeApp" ) ); //var testNet461Dlls = facadeTests // .Select( p => System.IO.Path.Combine( // p.Path.GetDirectory().ToString(), "bin", globalInfo.BuildConfiguration, "net461", p.Name + ".dll" ) ); //Cake.Information( $"Testing: {string.Join( ", ", testNet461Dlls )}" ); //Cake.NUnit( testNet461Dlls, new NUnitSettings() { Framework = "v4.5" } ); }); Task("Push-NuGet-Packages") .IsDependentOn("Create-NuGet-Packages") .IsDependentOn("Run-CKSetup-On-IntegrationTests-AllPackages-Net461-With-CKSetup-Net461") .IsDependentOn("Run-IntegrationTests") .IsDependentOn("Run-Facade-App-Tests") .WithCriteria(() => gitInfo.IsValid) .Does(() => { StandardPushNuGetPackages(globalInfo, releasesDir); }); Task("Default").IsDependentOn("Push-NuGet-Packages"); }
/// <summary> /// Creates a new <see cref="StandardGlobalInfo"/> initialized by the /// current environment. /// </summary> /// <param name="gitInfo">The git info.</param> /// <returns>A new info object.</returns> StandardGlobalInfo CreateStandardGlobalInfo(SimpleRepositoryInfo gitInfo) { var result = new StandardGlobalInfo(Cake, gitInfo); // By default: if (!gitInfo.IsValid) { if (Cake.InteractiveMode() != InteractiveMode.NoInteraction && Cake.ReadInteractiveOption("PublishDirtyRepo", "Repository is not ready to be published. Proceed anyway?", 'Y', 'N') == 'Y') { Cake.Warning("GitInfo is not valid, but you choose to continue..."); result.IgnoreNoArtifactsToProduce = true; } else { // On Appveyor, we let the build run: this gracefully handles Pull Requests. if (Cake.AppVeyor().IsRunningOnAppVeyor) { result.IgnoreNoArtifactsToProduce = true; } else { Cake.TerminateWithError("Repository is not ready to be published."); } } // When the gitInfo is not valid, we do not try to push any packages, even if the build continues // (either because the user choose to continue or if we are on the CI server). // We don't need to worry about feeds here. } else { // gitInfo is valid: it is either ci or a release build. var v = gitInfo.Info.FinalSemVersion; // If a /LocalFeed/ directory exists above, we publish the packages in it. var localFeedRoot = Cake.FindDirectoryAbove("LocalFeed"); if (localFeedRoot != null) { if (v.AsCSVersion == null) { if (v.Prerelease.EndsWith(".local")) { // Local releases must not be pushed on any remote and are copied to LocalFeed/Local // feed (if LocalFeed/ directory above exists). result.IsLocalCIRelease = true; result.LocalFeedPath = System.IO.Path.Combine(localFeedRoot, "Local"); } else { // CI build versions are routed to LocalFeed/CI result.LocalFeedPath = System.IO.Path.Combine(localFeedRoot, "CI"); } } else { // Release or prerelease go to LocalFeed/Release result.LocalFeedPath = System.IO.Path.Combine(localFeedRoot, "Release"); } System.IO.Directory.CreateDirectory(result.LocalFeedPath); } else { result.IsLocalCIRelease = v.Prerelease.EndsWith(".local"); } // Creating the right remote feed. if (!result.IsLocalCIRelease && (Cake.InteractiveMode() == InteractiveMode.NoInteraction || Cake.ReadInteractiveOption("PushToRemote", "Push to Remote feeds?", 'Y', 'N') == 'Y')) { result.PushToRemote = true; } } return(result); }
public Build() { var releasesDir = Cake.Directory("CodeCakeBuilder/Releases"); string configuration = null; SimpleRepositoryInfo gitInfo = null; var solution = Cake.ParseSolution("CK-DB.sln"); var CKDBProjectNames = new HashSet <string>(solution.Projects.Where(p => p.Name.StartsWith("CK.")).Select(pub => pub.Name)); string CKDatabaseVersion = null; Dictionary <string, string> DependentPackages = null; Dictionary <string, string> IntegrationDependentPackages = null; Task("Check-Dependencies") .Does(() => { var allPackages = solution.Projects .Where(p => p.Name.StartsWith("CK.")) .Select(p => new { Project = p, PackageConfig = p.Path.GetDirectory().CombineWithFilePath("packages.config").FullPath }) .Where(p => System.IO.File.Exists(p.PackageConfig)) .SelectMany(p => XDocument.Load(p.PackageConfig) .Root .Elements("package") .Select(e => { e.AddAnnotation(p.Project); return(e); })) .ToList(); var byPackage = allPackages .GroupBy(e => e.Attribute("id").Value, e => new { ProjectName = e.Annotation <SolutionProject>().Name, Version = e.Attribute("version").Value }); var multiVersions = byPackage.Where(g => g.GroupBy(x => x.Version).Count() > 1); if (multiVersions.Any()) { var conflicts = multiVersions.Select(e => Environment.NewLine + " - " + e.Key + ":" + Environment.NewLine + " - " + string.Join(Environment.NewLine + " - ", e.GroupBy(x => x.Version).Select(x => x.Key + " in " + string.Join(", ", x.Select(xN => xN.ProjectName))))); Cake.TerminateWithError($"Dependency versions differ for:{Environment.NewLine}{string.Join( Environment.NewLine, conflicts )}"); } CKDatabaseVersion = byPackage.Single(e => e.Key == "CK.StObj.Model").First().Version; // Use Tests/CK.DB.Actor.Tests/packages.config for packages' versions that are not the CK-DB ones. XDocument aclPackagesConfig = XDocument.Load("Tests/CK.DB.Actor.Tests/packages.config"); var pp = aclPackagesConfig.Root.Descendants("package").Where(e => !CKDBProjectNames.Contains((string)e.Attribute("id"))); DependentPackages = pp.ToDictionary(e => (string)e.Attribute("id"), e => (string)e.Attribute("version")); }); Task("Check-Repository") .IsDependentOn("Check-Dependencies") .Does(() => { gitInfo = Cake.GetSimpleRepositoryInfo(); if (!gitInfo.IsValid) { if (Cake.IsInteractiveMode() && Cake.ReadInteractiveOption("Repository is not ready to be published. Proceed anyway?", 'Y', 'N') == 'Y') { Cake.Warning("GitInfo is not valid, but you choose to continue..."); } else { throw new Exception("Repository is not ready to be published."); } } IntegrationDependentPackages = new Dictionary <string, string>(DependentPackages); foreach (var n in CKDBProjectNames) { IntegrationDependentPackages.Add(n, gitInfo.NuGetVersion); } configuration = gitInfo.IsValidRelease && gitInfo.PreReleaseName.Length == 0 ? "Release" : "Debug"; Cake.Information("Publishing {0} in {1}.", gitInfo.SemVer, configuration); }); Task("Clean") .IsDependentOn("Check-Repository") .Does(() => { Cake.CleanDirectories("**/bin/" + configuration, d => !d.Path.Segments.Contains("CodeCakeBuilder")); Cake.CleanDirectories("**/obj/" + configuration, d => !d.Path.Segments.Contains("CodeCakeBuilder")); Cake.CleanDirectories(releasesDir); }); Task("Restore-NuGet-Packages") .Does(() => { Cake.NuGetRestore("CK-DB.sln"); }); Task("Build") .IsDependentOn("Clean") .IsDependentOn("Restore-NuGet-Packages") .IsDependentOn("Check-Repository") .Does(() => { using (var tempSln = Cake.CreateTemporarySolutionFile("CK-DB.sln")) { tempSln.ExcludeProjectsFromBuild("CodeCakeBuilder"); Cake.MSBuild(tempSln.FullPath, settings => { settings.Configuration = configuration; settings.Verbosity = Verbosity.Minimal; // Always generates Xml documentation. Relies on this definition in the csproj files: // // <PropertyGroup Condition=" $(GenerateDocumentation) != '' "> // <DocumentationFile>bin\$(Configuration)\$(AssemblyName).xml</DocumentationFile> // </PropertyGroup> // settings.Properties.Add("GenerateDocumentation", new[] { "true" }); }); } }); Task("Unit-Testing") .IsDependentOn("Build") .WithCriteria(() => gitInfo.IsValidRelease) .Does(() => { var testDlls = solution.Projects .Where(p => p.Name.EndsWith(".Tests")) .Select(p => p.Path.GetDirectory().CombineWithFilePath("bin/" + configuration + "/" + p.Name + ".dll")); Cake.Information("Testing: {0}", string.Join(", ", testDlls.Select(p => p.GetFilename().ToString()))); Cake.NUnit(testDlls, new NUnitSettings() { Framework = "v4.5" }); }); Task("Create-NuGet-Packages") .IsDependentOn("Unit-Testing") .Does(() => { Cake.CreateDirectory(releasesDir); var settings = new NuGetPackSettings() { Version = gitInfo.NuGetVersion, BasePath = Cake.Environment.WorkingDirectory, OutputDirectory = releasesDir }; Cake.CopyFiles("CodeCakeBuilder/NuSpec/*.nuspec", releasesDir); foreach (var nuspec in Cake.GetFiles(releasesDir.Path + "/*.nuspec")) { TransformText(nuspec, configuration, gitInfo, CKDatabaseVersion); Cake.NuGetPack(nuspec, settings); } Cake.DeleteFiles(releasesDir.Path + "/*.nuspec"); }); Task("Run-IntegrationTests") .IsDependentOn("Create-NuGet-Packages") .WithCriteria(() => gitInfo.IsValid) .WithCriteria(() => !Cake.IsInteractiveMode() || Cake.ReadInteractiveOption("Run integration tests?", 'Y', 'N') == 'Y') .Does(() => { var integrationSolution = "IntegrationTests/IntegrationTests.sln"; var integration = Cake.ParseSolution(integrationSolution); var projects = integration.Projects .Where(p => p.Name != "CodeCakeBuilder") .Select(p => new { CSProj = p.Path.FullPath, ConfigFile = p.Path.GetDirectory().CombineWithFilePath("packages.config").FullPath }) .Where(p => System.IO.File.Exists(p.ConfigFile)); // Cleans all the existing IntegrationTests/packages. // The CodeCakeBuilder restore will get them (from Release for CK-DB packages). Cake.CleanDirectory("IntegrationTests/packages"); foreach (var config in projects.Select(p => p.ConfigFile)) { XDocument doc = XDocument.Load(config); int countRef = 0; foreach (var p in doc.Root.Elements("package")) { string packageName = p.Attribute("id").Value; if (IntegrationDependentPackages.ContainsKey(packageName)) { string depVersion = IntegrationDependentPackages[packageName]; if (p.Attribute("version").Value != depVersion) { p.SetAttributeValue("version", depVersion); ++countRef; } } } if (countRef > 0) { Cake.Information($"Updated {countRef} in file {config}."); doc.Save(config); } } foreach (var csproj in projects.Select(p => p.CSProj)) { XDocument doc = XDocument.Load(csproj); int countRef = 0; var projection = doc.Root.Descendants(msBuild + "Reference") .Select(e => new { Reference = e, IncludeAttr = e.Attribute("Include"), HintPathElement = e.Element(msBuild + "HintPath"), }); var filtered = projection.Where(e => e.HintPathElement != null && e.IncludeAttr != null && e.HintPathElement.Value.StartsWith(@"..\packages\")); var final = filtered.Select(e => new { E = e, ProjectName = new AssemblyName(e.IncludeAttr.Value).Name }) .Where(e => IntegrationDependentPackages.ContainsKey(e.ProjectName)); foreach (var p in final) { var version = IntegrationDependentPackages[p.ProjectName]; var path = p.E.HintPathElement.Value.Split('\\'); var newFolder = p.ProjectName + '.' + version; if (path[2] != newFolder) { path[2] = newFolder; p.E.HintPathElement.Value = string.Join("\\", path); ++countRef; } } if (countRef > 0) { Cake.Information($"Updated {countRef} references in file {csproj}."); doc.Save(csproj); } } Cake.NuGetRestore(integrationSolution); Cake.MSBuild("IntegrationTests/CodeCakeBuilder/CodeCakeBuilder.csproj", settings => { settings.Configuration = configuration; settings.Verbosity = Verbosity.Minimal; }); if (Cake.StartProcess($"IntegrationTests/CodeCakeBuilder/bin/{configuration}/CodeCakeBuilder.exe", "-" + InteractiveAliases.NoInteractionArgument) != 0) { Cake.TerminateWithError("Error in IntegrationTests."); } }); Task("Push-NuGet-Packages") .IsDependentOn("Create-NuGet-Packages") .IsDependentOn("Run-IntegrationTests") .WithCriteria(() => gitInfo.IsValid) .Does(() => { IEnumerable <FilePath> nugetPackages = Cake.GetFiles(releasesDir.Path + "/*.nupkg"); if (Cake.IsInteractiveMode()) { var localFeed = Cake.FindDirectoryAbove("LocalFeed"); if (localFeed != null) { Cake.Information("LocalFeed directory found: {0}", localFeed); if (Cake.ReadInteractiveOption("Do you want to publish to LocalFeed?", 'Y', 'N') == 'Y') { Cake.CopyFiles(nugetPackages, localFeed); } } } if (gitInfo.IsValidRelease) { if (gitInfo.PreReleaseName == "" || gitInfo.PreReleaseName == "rc" || gitInfo.PreReleaseName == "prerelease") { PushNuGetPackages("NUGET_API_KEY", "https://www.nuget.org/api/v2/package", nugetPackages); } else { // An alpha, beta, delta, epsilon, gamma, kappa goes to invenietis-preview. PushNuGetPackages("MYGET_PREVIEW_API_KEY", "https://www.myget.org/F/invenietis-preview/api/v2/package", nugetPackages); } } else { Debug.Assert(gitInfo.IsValidCIBuild); PushNuGetPackages("MYGET_CI_API_KEY", "https://www.myget.org/F/invenietis-ci/api/v2/package", nugetPackages); } }); Task("Default").IsDependentOn("Push-NuGet-Packages"); }
static int Main(string[] args) { try { var app = new CommandLineApplication(); app.Name = "sgv"; app.Description = "SimpleGitVersion commands."; app.HelpOption("-?|-h|--help"); app.VersionOption("--version", GetVersion, GetInformationalVersion); var optVerbose = app.Option("-v|--verbose", "Verbose output", CommandOptionType.NoValue); app.Command("info", c => { c.Description = "Display SimpleGitVersion information from Git repository."; var optionProject = c.Option("-p|--project <PATH>", "Path to a project, solution or any path under the solution directory, default is current directory", CommandOptionType.SingleValue); c.HelpOption("-?|-h|--help"); c.OnExecute(() => { ConsoleLoggerAdapter logger = new ConsoleLoggerAdapter(true); string path = optionProject.Value() ?? Directory.GetCurrentDirectory(); SimpleRepositoryInfo info = SimpleRepositoryInfo.LoadFromPath(logger, path, (log, hasRepoXml, options) => { options.IgnoreDirtyWorkingFolder = true; }); return(0); }); }); app.Command("prebuild", c => { c.Description = "Creates or updates Properties/SGVVersionInfo.cs files from Git repository."; var optionProject = c.Option("-p|--project <PATH>", "Path to project, default is current directory", CommandOptionType.SingleValue); c.HelpOption("-?|-h|--help"); c.OnExecute(() => { ConsoleLoggerAdapter logger = new ConsoleLoggerAdapter(optVerbose.HasValue()); string path = optionProject.Value() ?? Directory.GetCurrentDirectory(); var ctx = new DNXSolution(path, logger); if (ctx.IsValid) { var project = ctx.FindFromPath(path); if (project != null) { project.CreateOrUpdateSGVVersionInfoFile(); } else { logger.Warn("Project not found."); } } return(0); }); }); app.Command("update", c => { c.Description = "Updates version properties in project.json files based on Git repository."; var optionProject = c.Option("-p|--project <PATH>", "Path to project, default is current directory", CommandOptionType.SingleValue); c.HelpOption("-?|-h|--help"); c.OnExecute(() => { ConsoleLoggerAdapter logger = new ConsoleLoggerAdapter(optVerbose.HasValue()); string path = optionProject.Value() ?? Directory.GetCurrentDirectory(); var ctx = new DNXSolution(path, logger); if (ctx.IsValid) { ctx.UpdateProjectFiles(); } return(0); }); }); app.Command("restore", c => { c.Description = "Restores project.json files that differ only by version properties for this solution."; var optionProject = c.Option("-p|--project <PATH>", "Path to project, default is current directory", CommandOptionType.SingleValue); c.HelpOption("-?|-h|--help"); c.OnExecute(() => { ConsoleLoggerAdapter logger = new ConsoleLoggerAdapter(optVerbose.HasValue()); string path = optionProject.Value() ?? Directory.GetCurrentDirectory(); var ctx = new DNXSolution(path, logger); if (ctx.IsValid) { ctx.RestoreProjectFilesFromGitThatDifferOnlyByVersion(); } return(0); }); }); // Show help information if no subcommand/option was specified. app.OnExecute(() => { app.ShowHelp(); return(2); }); return(app.Execute(args)); } catch (Exception exception) { Console.WriteLine("Error: {0}", exception.Message); return(1); } }