From 6644049e29b87c48d3a87de7cdfd7933717e477c Mon Sep 17 00:00:00 2001 From: Phil Oyston Date: Thu, 26 Sep 2019 12:38:30 +0100 Subject: [PATCH] +semver: breaking - #10 - Upgrade to support Elasticsearch v6 (#11) * #10 Updates library to latest elasticsearch v6 NEST libraries and upgrades supported frameworks to: net461 and netstandard2.0 --- .cake/Artifacts-ARM.cake | 20 ++ .cake/Artifacts-Copy.cake | 58 +++++ .cake/Artifacts-DotNetCore-Ef.cake | 163 ++++++++++++ .cake/Build-DotNetCore.cake | 16 ++ .cake/Build-MsBuild.cake | 15 ++ .cake/CI-AppVeyor.cake | 24 ++ .cake/CI-Azure-DevOps.cake | 34 +++ .cake/CI.cake | 14 ++ .cake/Configuration-Version.cake | 100 ++++++++ .cake/Configuration.cake | 238 ++++++++++++++++++ .cake/Npm-RunScript.cake | 61 +++++ .cake/Publish-MsBuild-Folder.cake | 35 +++ .cake/Publish-MsBuild-WebDeploy.cake | 27 ++ .cake/Publish-Pack-DotNetCore.cake | 32 +++ .cake/Publish-Pack-NuGet.cake | 23 ++ .cake/Publish-Zip-DotNetCore.cake | 32 +++ .cake/Publish-Zip-MsBuild.cake | 28 +++ .cake/Restore-DotNetCore.cake | 5 + .cake/Restore-NuGet.cake | 8 + .cake/Test-DotNetCore.cake | 52 ++++ .cake/Test-NUnit2.cake | 54 ++++ .cake/Test-NUnit3.cake | 58 +++++ .cake/Test-XUnit2.cake | 52 ++++ .gitignore | 197 +++++++++++++-- GitVersion.yml | 22 ++ GitVersionConfig.yaml | 12 - Nest.Queryify.sln | 9 +- appveyor.yml | 12 - azure-pipelines.yml | 101 ++++++++ build.cake | 238 +----------------- build.ps1 | 168 ++++++++++--- src/Nest.Queryify/Nest.Queryify.csproj | 14 +- .../Nest.Queryify.Tests.csproj | 28 +-- .../Queries/Specs/MultiSearchQuerySpecs.cs | 3 +- .../Queries/Specs/SearchQuerySpecs.cs | 3 +- .../SearchQueryWithReturnDocumentSpecs.cs | 4 +- tools/packages.config | 4 + 37 files changed, 1619 insertions(+), 345 deletions(-) create mode 100644 .cake/Artifacts-ARM.cake create mode 100644 .cake/Artifacts-Copy.cake create mode 100644 .cake/Artifacts-DotNetCore-Ef.cake create mode 100644 .cake/Build-DotNetCore.cake create mode 100644 .cake/Build-MsBuild.cake create mode 100644 .cake/CI-AppVeyor.cake create mode 100644 .cake/CI-Azure-DevOps.cake create mode 100644 .cake/CI.cake create mode 100644 .cake/Configuration-Version.cake create mode 100644 .cake/Configuration.cake create mode 100644 .cake/Npm-RunScript.cake create mode 100644 .cake/Publish-MsBuild-Folder.cake create mode 100644 .cake/Publish-MsBuild-WebDeploy.cake create mode 100644 .cake/Publish-Pack-DotNetCore.cake create mode 100644 .cake/Publish-Pack-NuGet.cake create mode 100644 .cake/Publish-Zip-DotNetCore.cake create mode 100644 .cake/Publish-Zip-MsBuild.cake create mode 100644 .cake/Restore-DotNetCore.cake create mode 100644 .cake/Restore-NuGet.cake create mode 100644 .cake/Test-DotNetCore.cake create mode 100644 .cake/Test-NUnit2.cake create mode 100644 .cake/Test-NUnit3.cake create mode 100644 .cake/Test-XUnit2.cake create mode 100644 GitVersion.yml delete mode 100644 GitVersionConfig.yaml delete mode 100644 appveyor.yml create mode 100644 azure-pipelines.yml create mode 100644 tools/packages.config diff --git a/.cake/Artifacts-ARM.cake b/.cake/Artifacts-ARM.cake new file mode 100644 index 0000000..43a7da9 --- /dev/null +++ b/.cake/Artifacts-ARM.cake @@ -0,0 +1,20 @@ +Task("Artifacts:Copy:ARM") + .WithCriteria((ctx, config) => ctx.DirectoryExists("./src/arm") && ctx.GetSubDirectories("./src/arm").Any()) + .IsDependentOn("Build") + .IsDependeeOf("Publish") + .Does(config => +{ + var artifacts = $"{config.Artifacts.Root}/arm"; + EnsureDirectoryExists(artifacts); + foreach(var directory in GetSubDirectories("./src/arm")) + { + if(DirectoryExists(directory)) { + var copyFrom = directory; + var copyTo = $"{artifacts}/{directory.GetDirectoryName()}"; + Information("{0} -> {1}", copyFrom, copyTo); + EnsureDirectoryExists(copyTo); + CopyDirectory(directory, copyTo); + config.Artifacts.Add(ArtifactTypeOption.Other, directory.GetDirectoryName(), directory.FullPath); + } + } +}); \ No newline at end of file diff --git a/.cake/Artifacts-Copy.cake b/.cake/Artifacts-Copy.cake new file mode 100644 index 0000000..5a53c43 --- /dev/null +++ b/.cake/Artifacts-Copy.cake @@ -0,0 +1,58 @@ +#load "Configuration.cake" + +public static Configuration IncludeArtifactCopyTarget(this Configuration configuration, DirectoryPath sourceDirectory) +{ + var copyList = new HashSet(); + if(configuration.TaskParameters.TryGetValue("Artifacts:Copy__Items", out object value) && value is HashSet) + { + copyList = value as HashSet; + } + else + { + configuration.TaskParameters.Add("Artifacts:Copy__Items", copyList); + } + + copyList.Add(sourceDirectory); + + return configuration; +} + +public static bool HasArtifactCopyTargets(this Configuration configuration) +{ + var copyList = new HashSet(); + if(configuration.TaskParameters.TryGetValue("Artifacts:Copy__Items", out object value) && value is HashSet) + { + copyList = value as HashSet; + } + + return copyList.Any(); +} + +public static IEnumerable GetArtifactCopyTargets(this Configuration configuration) +{ + var copyList = new HashSet(); + if(configuration.TaskParameters.TryGetValue("Artifacts:Copy__Items", out object value) && value is HashSet) + { + copyList = value as HashSet; + } + return copyList; +} + +Task("Artifacts:Copy") + .WithCriteria((ctx, config) => config.HasArtifactCopyTargets()) + .IsDependentOn("Build") + .IsDependeeOf("Publish") + .Does(config => +{ + var artifacts = $"{config.Artifacts.Root}"; + EnsureDirectoryExists(artifacts); + foreach(var directory in config.GetArtifactCopyTargets()) + { + var copyFrom = directory; + var copyTo = $"{artifacts}/{directory.GetDirectoryName()}"; + Information("{0} -> {1}", copyFrom, copyTo); + EnsureDirectoryExists(copyTo); + CopyDirectory(directory, copyTo); + config.Artifacts.Add(ArtifactTypeOption.Other, directory.GetDirectoryName(), directory.FullPath); + } +}); \ No newline at end of file diff --git a/.cake/Artifacts-DotNetCore-Ef.cake b/.cake/Artifacts-DotNetCore-Ef.cake new file mode 100644 index 0000000..0d94677 --- /dev/null +++ b/.cake/Artifacts-DotNetCore-Ef.cake @@ -0,0 +1,163 @@ +#load "Configuration.cake" +#addin nuget:?package=Newtonsoft.Json&version=12.0.1 +using Newtonsoft.Json; + +public class EfMigration +{ + public string Id { get; set; } + public string Name { get; set; } + public string SafeName { get; set; } +} + +public class EfContext +{ + public string FullName { get; set; } + public string SafeName { get; set; } + public string Name { get; set; } + public string AssemblyQualifiedName { get; set; } +} + +IEnumerable GetAllDbContexts(DirectoryPath workingDirectory, string configuration) +{ + var settings = new ProcessSettings() + { + WorkingDirectory = workingDirectory, + RedirectStandardOutput = true + }; + + settings.Arguments = string.Format("ef dbcontext list --configuration {0} --json --prefix-output", configuration); + var list = Enumerable.Empty(); + + using(var process = StartAndReturnProcess("dotnet", settings)) + { + process.WaitForExit(); + if(process.GetExitCode() == 0) + { + try + { + var outputAsJson = string.Join(Environment.NewLine, process.GetStandardOutput().Where(l => l.StartsWith("data:")).Select(l => l.Replace("data:", ""))); + list = JsonConvert.DeserializeObject>(outputAsJson); + Verbose("Found {0} Db contexts", list.Count()); + } + catch(Exception exception) + { + Error("Unable to determine db context's for {0} : {1}", workingDirectory, exception.Message); + } + } + } + return list.ToList(); +} + +IEnumerable GetMigrationsForContext(string dbContext, DirectoryPath workingDirectory, string configuration) +{ + var settings = new ProcessSettings() + { + WorkingDirectory = workingDirectory, + RedirectStandardOutput = true + }; + + settings.Arguments = string.Format("ef migrations list --configuration {0} --context {1} --json --prefix-output", configuration, dbContext); + + var list = Enumerable.Empty(); + using(var process = StartAndReturnProcess("dotnet", settings)) + { + process.WaitForExit(); + if(process.GetExitCode() == 0) + { + try + { + var outputAsJson = string.Join(Environment.NewLine, process.GetStandardOutput().Where(l => l.StartsWith("data:")).Select(l => l.Replace("data:", ""))); + list = JsonConvert.DeserializeObject>(outputAsJson); + } + catch(Exception exception) + { + Error("Unable to determine db migration list for {0} : {1}", dbContext, exception.Message); + } + } + } + return list; +} + +public static Configuration IncludeAsEfDbContext(this Configuration configuration, Func includeAsEFDbContext) +{ + var projects = new HashSet(); + if(configuration.TaskParameters.TryGetValue("Artifacts:DotNetCore:Ef:Migration-Script", out object value) && value is HashSet) + { + projects = value as HashSet; + } + else + { + configuration.TaskParameters.Add("Artifacts:DotNetCore:Ef:Migration-Script", projects); + } + + var projectsToInclude = configuration.Solution.Projects.Where(includeAsEFDbContext).ToList(); + + if(projectsToInclude != null && projectsToInclude.Any()) + { + projects.UnionWith(projectsToInclude); + } + + return configuration; +} + +public static bool HasCustomEfDbContextTargets(this Configuration configuration) +{ + var projectList = configuration.GetEfDbContextTargets(); + return projectList?.Any() ?? false; +} + +public static IEnumerable GetEfDbContextTargets(this Configuration configuration) +{ + var projects = new HashSet(); + if(configuration.TaskParameters.TryGetValue("Artifacts:DotNetCore:Ef:Migration-Script", out object value) && value is HashSet) + { + projects = value as HashSet; + } + return projects; +} + +Task("Artifacts:DotNetCore:Ef:Migration-Script") + .IsDependentOn("Build") + .IsDependeeOf("Publish") + .Does(config => +{ + var efProjects = (config.HasCustomEfDbContextTargets() ? config.GetEfDbContextTargets() : config.Solution.Projects).ToList(); + + Information("Generating scripts for {0} projects", efProjects.Count()); + foreach(var project in efProjects) { + var assemblyName = config.Solution.GetProjectName(project); + var workingDirectory = project.ProjectFilePath.GetDirectory(); + var availableDbContexts = GetAllDbContexts(workingDirectory, config.Solution.BuildConfiguration).ToList(); + + if(availableDbContexts.Any()) + { + Information("Generating scripts for {0} containing {1} contexts", assemblyName, availableDbContexts.Count); + foreach(var dbContext in availableDbContexts) + { + Information("Generating Sql Script for {0}", dbContext.SafeName); + var migrations = GetMigrationsForContext(dbContext.SafeName, workingDirectory, config.Solution.BuildConfiguration); + + var sqlScript = MakeAbsolute(File($"{config.Artifacts.Root}/sql/{dbContext.SafeName}.sql")); + if(FileExists(sqlScript)) { + DeleteFile(sqlScript); + } + + var settings = new ProcessSettings() + { + WorkingDirectory = workingDirectory + }; + + settings.Arguments = string.Format("ef migrations script -i -o {0} --configuration {1} --context {2}", sqlScript, config.Solution.BuildConfiguration, dbContext.SafeName); + + using(var process = StartAndReturnProcess("dotnet", settings)) + { + process.WaitForExit(); + Verbose("Exit code: {0}", process.GetExitCode()); + } + + config.Artifacts.Add(ArtifactTypeOption.Other, sqlScript.GetFilename().ToString(), sqlScript); + } + } + } + +}); diff --git a/.cake/Build-DotNetCore.cake b/.cake/Build-DotNetCore.cake new file mode 100644 index 0000000..10388f7 --- /dev/null +++ b/.cake/Build-DotNetCore.cake @@ -0,0 +1,16 @@ +#load "Configuration.cake" + +Task("Build:DotNetCore") + .IsDependentOn("Restore") + .IsDependeeOf("Build") + .Does(config => +{ + var buildSettings = new DotNetCoreBuildSettings() { + NoRestore = true, + Configuration = config.Solution.BuildConfiguration, + NoIncremental = true, + Verbosity = DotNetCoreVerbosity.Minimal + }; + + DotNetCoreBuild(config.Solution.Path.ToString(), buildSettings); +}); \ No newline at end of file diff --git a/.cake/Build-MsBuild.cake b/.cake/Build-MsBuild.cake new file mode 100644 index 0000000..acad65a --- /dev/null +++ b/.cake/Build-MsBuild.cake @@ -0,0 +1,15 @@ +#load "Configuration.cake" + +Task("Build:MsBuild") + .IsDependentOn("Restore") + .IsDependeeOf("Build") + .Does(config => +{ + MSBuild(config.Solution.Path.ToString(), c => c + .SetConfiguration(config.Solution.BuildConfiguration) + .SetVerbosity(Verbosity.Minimal) + .UseToolVersion(MSBuildToolVersion.VS2017) + .WithWarningsAsError() + .WithTarget("Build") + ); +}); \ No newline at end of file diff --git a/.cake/CI-AppVeyor.cake b/.cake/CI-AppVeyor.cake new file mode 100644 index 0000000..102eb54 --- /dev/null +++ b/.cake/CI-AppVeyor.cake @@ -0,0 +1,24 @@ +#load "Configuration.cake" + +Task("CI:AppVeyor:UploadArtifacts") + .WithCriteria((ctx, config) => BuildSystem.IsRunningOnAppVeyor) + .IsDependentOn("Publish") + .IsDependeeOf("CI:UploadArtifacts") + .Does(config => +{ + foreach(var artifact in config.Artifacts) { + if(FileExists(artifact.Path)) { + BuildSystem.AppVeyor.UploadArtifact(artifact.Path, new AppVeyorUploadArtifactsSettings { + ArtifactType = artifact.Type == ArtifactTypeOption.WebDeploy ? AppVeyorUploadArtifactType.WebDeployPackage : AppVeyorUploadArtifactType.Auto + }); + } + } +}); + +Task("CI:AppVeyor:UpdateBuildNumber") + .IsDependeeOf("CI:UpdateBuildNumber") + .WithCriteria((ctx, config) => AppVeyor.IsRunningOnAppVeyor) + .Does(config => +{ + AppVeyor.UpdateBuildVersion(config.Version.FullSemVersion +"." +AppVeyor.Environment.Build.Number); +}); \ No newline at end of file diff --git a/.cake/CI-Azure-DevOps.cake b/.cake/CI-Azure-DevOps.cake new file mode 100644 index 0000000..28bcc59 --- /dev/null +++ b/.cake/CI-Azure-DevOps.cake @@ -0,0 +1,34 @@ +#load "Configuration.cake" + +Task("CI:VSTS:UploadArtifacts") + .WithCriteria((ctx, config) => BuildSystem.IsRunningOnAzurePipelinesHosted || TFBuild.IsRunningOnAzurePipelines) + .IsDependentOn("Publish") + .IsDependeeOf("CI:UploadArtifacts") + .Does(config => +{ + Information("Uploading artifacts from {0}", config.Artifacts.Root); + TFBuild.Commands.UploadArtifact("artifacts", config.Artifacts.Root.ToString(), "artifacts"); +}); + +Task("CI:VSTS:UpdateBuildNumber") + .IsDependeeOf("CI:UpdateBuildNumber") + .WithCriteria((ctx, config) => BuildSystem.IsRunningOnAzurePipelinesHosted || TFBuild.IsRunningOnAzurePipelines) + .Does(config => +{ + Information( + @"Repository: + Branch: {0} + SourceVersion: {1} + Shelveset: {2}", + BuildSystem.TFBuild.Environment.Repository.Branch, + BuildSystem.TFBuild.Environment.Repository.SourceVersion, + BuildSystem.TFBuild.Environment.Repository.Shelveset + ); + + TFBuild.Commands.UpdateBuildNumber(config.Version.FullSemVersion); + TFBuild.Commands.SetVariable("GitVersion.Version", config.Version.Version); + TFBuild.Commands.SetVariable("GitVersion.SemVer", config.Version.SemVersion); + TFBuild.Commands.SetVariable("GitVersion.InformationalVersion", config.Version.InformationalVersion); + TFBuild.Commands.SetVariable("GitVersion.FullSemVer", config.Version.FullSemVersion); + TFBuild.Commands.SetVariable("Cake.Version", config.Version.CakeVersion); +}); \ No newline at end of file diff --git a/.cake/CI.cake b/.cake/CI.cake new file mode 100644 index 0000000..b037189 --- /dev/null +++ b/.cake/CI.cake @@ -0,0 +1,14 @@ +#load "CI-Azure-DevOps.cake" +#load "CI-AppVeyor.cake" + +Task("CI") + .IsDependentOn("CI:UpdateBuildNumber") + .IsDependeeOf("Default") + .IsDependentOn("CI:UploadArtifacts"); + +Task("CI:UpdateBuildNumber") + .IsDependeeOf("CI").Does(config => Information("Build Number: {0}", config.Version.SemVersion)); + +Task("CI:UploadArtifacts") + .IsDependeeOf("CI") + .IsDependentOn("Publish"); \ No newline at end of file diff --git a/.cake/Configuration-Version.cake b/.cake/Configuration-Version.cake new file mode 100644 index 0000000..97a6027 --- /dev/null +++ b/.cake/Configuration-Version.cake @@ -0,0 +1,100 @@ +#tool "nuget:?package=GitVersion.CommandLine&version=5.0.1" + +public class BuildVersion { + public FilePath VersionAssemblyInfo { get; private set; } + public string Version { get; private set; } + public string SemVersion { get; private set; } + public string CakeVersion { get; private set; } = typeof(ICakeContext).Assembly.GetName().Version.ToString(); + public string InformationalVersion { get; private set; } + public string FullSemVersion { get; private set; } + + public static BuildVersion DetermineBuildVersion(ICakeContext context) { + return new BuildVersion(context); + } + + private BuildVersion(ICakeContext context) { + VersionAssemblyInfo = context.Argument("versionAssemblyInfo", "VersionAssemblyInfo.cs"); + + if(context.DirectoryExists(".git")) { + UseGitVersion(context); + } + else + { + UseVersionAssemblyInfo(context); + } + + LogVersionInformation(context); + + EnsureVersionInformation(); + } + + private void LogVersionInformation(ICakeContext context) { + if(context.Log.Verbosity == Verbosity.Diagnostic) { + context.Verbose("--- ENVIRONMENT ---"); + foreach(var s in context.EnvironmentVariables()) { + context.Verbose("{0} = {1}", s.Key, s.Value); + } + context.Verbose("-------------------"); + } + + context.Information($"{nameof(Version)} = {Version}"); + context.Information($"{nameof(SemVersion)} = {SemVersion}"); + context.Information($"{nameof(CakeVersion)} = {CakeVersion}"); + context.Information($"{nameof(InformationalVersion)} = {InformationalVersion}"); + context.Information($"{nameof(FullSemVersion)} = {FullSemVersion}"); + } + + private void UseVersionAssemblyInfo(ICakeContext context) { + if(context.FileExists(VersionAssemblyInfo)) { + context.Verbose($"Looking up semantic version from {VersionAssemblyInfo}"); + + var assemblyInfo = context.ParseAssemblyInfo(VersionAssemblyInfo); + Version = assemblyInfo.AssemblyVersion; + SemVersion = assemblyInfo.AssemblyInformationalVersion; + InformationalVersion = assemblyInfo.AssemblyInformationalVersion; + FullSemVersion = assemblyInfo.AssemblyVersion; + } + else + { + context.Error("Unable to calculate or retrieve version information"); + } + } + + private void UseGitVersion(ICakeContext context) { + var settings = new GitVersionSettings { + UpdateAssemblyInfo = true, + UpdateAssemblyInfoFilePath = VersionAssemblyInfo, + NoFetch = true + }; + settings.ArgumentCustomization = args => args.Append("-ensureassemblyinfo"); + context.Verbose($"Calculating semantic version...."); + + if(context.BuildSystem().IsLocalBuild || !context.HasArgument("GitVersionFromBuildServer")) + { + context.Verbose("Outputting semantic version as JSON"); + settings.OutputType = GitVersionOutput.Json; + var gitVersion = context.GitVersion(settings); + Version = gitVersion.MajorMinorPatch; + SemVersion = gitVersion.LegacySemVerPadded; + InformationalVersion = gitVersion.InformationalVersion; + FullSemVersion = gitVersion.FullSemVer; + } + else + { + // not working properly + context.Verbose("Outputting semantic version for BUILDSERVER"); + settings.OutputType = GitVersionOutput.BuildServer; + context.GitVersion(settings); + Version = context.EnvironmentVariable("GITVERSION_MAJORMINORPATCH"); + SemVersion = context.EnvironmentVariable("GITVERSION_LEGACYSEMVERPADDED"); + InformationalVersion = context.EnvironmentVariable("GITVERSION_INFORMATIONALVERSION"); + FullSemVersion = context.EnvironmentVariable("GITVERSION_FULLSEMVER"); + } + } + + private void EnsureVersionInformation() { + if(new [] { Version, SemVersion, FullSemVersion, InformationalVersion }.Any(string.IsNullOrWhiteSpace)) { + throw new Exception("Version information has not been determined, build failed!"); + } + } +} diff --git a/.cake/Configuration.cake b/.cake/Configuration.cake new file mode 100644 index 0000000..92e8916 --- /dev/null +++ b/.cake/Configuration.cake @@ -0,0 +1,238 @@ +#addin "Cake.Incubator&version=5.0.1" +#load "Configuration-Version.cake" + +const string _solutionFilePathPattern = "*.sln"; +const string _defaultBuildConfiguration = "Release"; + +Task("Noop"); + +Task("Default") + .IsDependentOn("Restore") + .IsDependentOn("Build") + .IsDependentOn("Test") + .IsDependentOn("Publish") + .IsDependentOn("Artifacts:List"); + +Task("Restore"); + +Task("Build") + .IsDependentOn("Restore"); + +Task("Test") + .IsDependentOn("Build"); + +Task("Publish") + .IsDependentOn("Test") + .IsDependeeOf("Artifacts:List"); + +Task("Artifacts:List") + .IsDependentOn("Publish") + .Does(config => { + foreach(var artifact in config.Artifacts) { + Information(artifact); + } + }); + +/* ************************************* */ + +public partial class Configuration { + public static Configuration Create(ISetupContext context) { + var config = new Configuration(context, _solutionFilePathPattern); + config.Log(context.Log); + return config; + } + + public static Configuration Create(ISetupContext context, Action configure) { + var config = new Configuration(context, _solutionFilePathPattern); + configure(config); + config.Log(context.Log); + return config; + } + + public static Configuration Create(ISetupContext context, string solutionFilePathPattern = _solutionFilePathPattern, Action configure = null) { + var config = new Configuration(context, solutionFilePathPattern); + configure?.Invoke(config); + config.Log(context.Log); + return config; + } + + public Dictionary TaskParameters { get; } = new Dictionary(); + + public BuildVersion Version { get; } + + public SolutionParameters Solution { get; } + + public ArtifactsParameters Artifacts { get; } + + private readonly ICakeContext context; + + private Configuration(ISetupContext context, string solutionFilePathPattern = "*.sln", string defaultBuildConfiguration = "Release", DirectoryPath artifactsRootPath = null) + { + this.context = context; + var solutionPath = context.GetFiles(solutionFilePathPattern).First(); + if(!context.FileExists(solutionPath)) { + throw new Exception("Unable to find valid solution file"); + } + + var buildConfiguration = context.Argument("configuration", defaultBuildConfiguration); + + Solution = new SolutionParameters(context, solutionPath, buildConfiguration); + + Version = BuildVersion.DetermineBuildVersion(context); + + Artifacts = new ArtifactsParameters(context, artifactsRootPath ?? context.Directory("artifacts")); + } + + public ICakeLog Logger => context.Log; + + public void Log(ICakeLog logger) + { + Solution.Log(logger); + } + +} +public enum ArtifactTypeOption { + Zip, + WebDeploy, + NuGet, + TestResults, + Other +} + +public struct Artifact { + public ArtifactTypeOption Type { get; set; } + public string Category { get; set; } + public string Name { get; set; } + public FilePath Path { get; set; } + + public Artifact(ArtifactTypeOption type, string name, FilePath path, string category = "N/A") + { + Type = type; + Name = name; + Path = path; + Category = category; + } + + public override string ToString() { + return $"{Name} ({Type}/{Category}) - {Path.FullPath}"; + } +} + +public class ArtifactsParameters : List { + + private readonly ICakeContext context; + public DirectoryPath Root { get; set; } + + public DirectoryPath GetRootFor(ArtifactTypeOption type) { + var directory = $"{Root}/{type:G}/"; + context.EnsureDirectoryExists(directory); + return context.Directory(directory); + } + + public ArtifactsParameters(ICakeContext context, DirectoryPath artifactsRootPath) { + this.context = context; + Root = context.MakeAbsolute(artifactsRootPath); + context.EnsureDirectoryExists(Root); + context.CleanDirectory(Root); + } + + public void Add(ArtifactTypeOption type, string name, FilePath path) { + Add(new Artifact(type, name, context.MakeAbsolute(path))); + } +} + +public class SolutionParameters { + private readonly ICakeContext context; + public SolutionParserResult Solution { get; } + public FilePath Path { get; } + + public string BuildConfiguration { get; } + public IEnumerable Projects { get; } = Enumerable.Empty(); + public IEnumerable WebProjects => Projects.Where(IsWebProject); + public IEnumerable TestProjects => Projects.Where(IsCliTestProject); + public IEnumerable NuGetProjects => Projects.Where(IsNuGetPackableProject); + public IEnumerable LibraryProjects => Projects.Where(IsLibraryProject); + + public SolutionParameters(ICakeContext context, FilePath solutionPath, string buildConfiguration) { + this.context = context; + Path = solutionPath; + BuildConfiguration = buildConfiguration; + Solution = context.ParseSolution(Path); + Projects = Solution.GetProjects().Select(p => context.ParseProject(p.Path, buildConfiguration)).ToList(); + } + + private ISet> WebProjectResolvers { get; } = new HashSet>() { + p => p.IsWebApplication(), + p => p.HasPackage("Microsoft.NET.Sdk.Functions") + }; + + private ISet> TestProjectResolvers { get; } = new HashSet>() { + p => p.IsTestProject() + }; + + private ISet> NuGetProjectResolvers { get; } = new HashSet>() { + p => !string.IsNullOrWhiteSpace(p?.NetCore?.PackageId) && p.NetCore.IsPackable && !p.NetCore.IsWeb + }; + + private ISet> LibraryProjectResolvers { get; } = new HashSet>() { + p => p.IsLibrary() + }; + + public SolutionParameters IncludeAsWebProject(Func includeFunc) { + WebProjectResolvers.Add(includeFunc); + return this; + } + + public SolutionParameters IncludeAsTestProject(Func includeFunc) { + TestProjectResolvers.Add(includeFunc); + return this; + } + + public SolutionParameters IncludeAsNuGetProject(Func includeFunc) { + NuGetProjectResolvers.Add(includeFunc); + return this; + } + + public SolutionParameters IncludeAsLibraryProject(Func includeFunc) { + LibraryProjectResolvers.Add(includeFunc); + return this; + } + + private bool IsWebProject(CustomProjectParserResult project) { + return WebProjectResolvers.Any(resolver => resolver(project)); + } + + private bool IsCliTestProject(CustomProjectParserResult project) { + return TestProjectResolvers.Any(resolver => resolver(project)); + } + + private bool IsNuGetPackableProject(CustomProjectParserResult project) { + return NuGetProjectResolvers.Any(resolver => resolver(project)); + } + + private bool IsLibraryProject(CustomProjectParserResult project) { + return LibraryProjectResolvers.Any(resolver => resolver(project)); + } + + public string GetProjectName(CustomProjectParserResult project) { + if(project == null) { + throw new ArgumentNullException(nameof(project)); + } + return string.IsNullOrWhiteSpace(project.AssemblyName) ? project.ProjectFilePath.GetFilenameWithoutExtension().ToString() : project.AssemblyName; + } + + public void Log(ICakeLog logger) { + logger.Information("------\nProjects - Total: {0}, Web: {1}, Test: {2}, NuGet: {3}, Library: {4}\n------", Projects.Count(), WebProjects.Count(), TestProjects.Count(), NuGetProjects.Count(), LibraryProjects.Count()); + } +} + +const string logo = +" _ _ \n" + +" _ (_) | | \n" + +" ___| |_ ___ ____ ____ _ _ | | \n" + +" /___) _)/ _ \\ / ___) \\ | |/ || | \n" + +"|___ | |_| |_| | | | | | | | ( (_| | \n" + +"(___/ \\___)___/|_| |_|_|_| |_|\\____| \n" + +" "; + +Information(logo); diff --git a/.cake/Npm-RunScript.cake b/.cake/Npm-RunScript.cake new file mode 100644 index 0000000..ba89f8b --- /dev/null +++ b/.cake/Npm-RunScript.cake @@ -0,0 +1,61 @@ +#addin "nuget:?package=Cake.Npm&version=0.15.0" + +public partial class Configuration +{ + public Configuration RunNpmScript(string scriptName, string workingDirectory = "./") + { + Npm = new NpmConfiguration(context, scriptName, workingDirectory); + return this; + } + + public NpmConfiguration Npm { get; private set; } +} + +public class NpmConfiguration +{ + public string WorkingDirectory { get; } = "./"; + public string ScriptName { get; } = "ci"; + + private readonly ICakeContext cakeContext; + + public NpmConfiguration(ICakeContext cakeContext, string scriptName, string workingDirectory) + { + this.cakeContext = cakeContext; + ScriptName = scriptName; + WorkingDirectory = workingDirectory ?? "./"; + } + + public bool CanExecuteNpm { + get { + return cakeContext.FileExists($"{WorkingDirectory.TrimEnd('/')}/package.json"); + } + } +} + +Task("Npm").IsDependeeOf("Restore").IsDependentOn("Npm:Install").IsDependentOn("Npm:Build"); + +Task("Npm:Install") + .WithCriteria((ctx, config) => config.Npm.CanExecuteNpm) + .Does(config => +{ + var settings = new NpmInstallSettings(); + settings.WorkingDirectory = config.Npm.WorkingDirectory; + settings.LogLevel = NpmLogLevel.Silent; + settings.RedirectStandardError = false; + settings.RedirectStandardOutput = false; + NpmInstall(settings); +}); + +Task("Npm:Build") + .IsDependentOn("Npm:Install") + .WithCriteria((ctx, config) => config.Npm.CanExecuteNpm) + .Does(config => +{ + var settings = new NpmRunScriptSettings(); + settings.WorkingDirectory = config.Npm.WorkingDirectory; + settings.LogLevel = NpmLogLevel.Silent; + settings.RedirectStandardError = false; + settings.RedirectStandardOutput = false; + settings.ScriptName = config.Npm.ScriptName; + NpmRunScript(settings); +}); \ No newline at end of file diff --git a/.cake/Publish-MsBuild-Folder.cake b/.cake/Publish-MsBuild-Folder.cake new file mode 100644 index 0000000..bc73a00 --- /dev/null +++ b/.cake/Publish-MsBuild-Folder.cake @@ -0,0 +1,35 @@ +#load "Configuration.cake" + +Task("Publish:MsBuild") + .IsDependentOn("Build") + .IsDependeeOf("Publish") + .Does(config => +{ + foreach(var webProject in config.Solution.WebProjects) { + var assemblyName = config.Solution.GetProjectName(webProject); + var projectArtifactDirectory = $"{config.Artifacts.GetRootFor(ArtifactTypeOption.Zip)}/{assemblyName}"; + var artifactZipName = $"{assemblyName}.zip"; + var artifactZipFullPath = $"{projectArtifactDirectory}/{artifactZipName}"; + + MSBuild(webProject.ProjectFilePath, c => c + .SetConfiguration(config.Solution.BuildConfiguration) + .SetVerbosity(Verbosity.Quiet) + .UseToolVersion(MSBuildToolVersion.VS2017) + .WithWarningsAsError() + .WithTarget("Package") + .WithProperty("DeployTarget", "PipelinePreDeployCopyAllFilesToOneFolder") + .WithProperty("SkipInvalidConfigurations", "false") + .WithProperty("AutoParameterizationWebConfigConnectionStrings", "false") + .WithProperty("PackageTempRootDir", projectArtifactDirectory) + ); + + Zip($"{projectArtifactDirectory}/PackageTmp", artifactZipFullPath); + + DeleteDirectory($"{projectArtifactDirectory}/PackageTmp", new DeleteDirectorySettings { + Recursive = true, + Force = true + }); + + config.Artifacts.Add(ArtifactTypeOption.Zip, assemblyName, $"{artifactZipFullPath}"); + } +}); \ No newline at end of file diff --git a/.cake/Publish-MsBuild-WebDeploy.cake b/.cake/Publish-MsBuild-WebDeploy.cake new file mode 100644 index 0000000..44c6277 --- /dev/null +++ b/.cake/Publish-MsBuild-WebDeploy.cake @@ -0,0 +1,27 @@ +#load "Configuration.cake" + +Task("Publish:MsBuild") + .IsDependentOn("Build") + .IsDependeeOf("Publish") + .Does(config => +{ + foreach(var webProject in config.Solution.WebProjects) { + var assemblyName = config.Solution.GetProjectName(webProject); + var projectArtifactDirectory = $"{config.Artifacts.GetRootFor(ArtifactTypeOption.WebDeploy)}/{assemblyName}"; + var artifactZipName = $"{assemblyName}.zip"; + var artifactZipFullPath = $"{projectArtifactDirectory}/{artifactZipName}"; + + MSBuild(webProject.ProjectFilePath, c => c + .SetConfiguration(config.Solution.BuildConfiguration) + .SetVerbosity(Verbosity.Quiet) + .UseToolVersion(MSBuildToolVersion.VS2017) + .WithWarningsAsError() + .WithTarget("Package") + .WithProperty("PackageAsSingleFile", "true") + .WithProperty("SkipInvalidConfigurations", "false") + .WithProperty("AutoParameterizationWebConfigConnectionStrings", "false") + .WithProperty("PackageLocation", artifactZipFullPath) + ); + config.Artifacts.Add(ArtifactTypeOption.WebDeploy, assemblyName, $"{projectArtifactDirectory}"); + } +}); \ No newline at end of file diff --git a/.cake/Publish-Pack-DotNetCore.cake b/.cake/Publish-Pack-DotNetCore.cake new file mode 100644 index 0000000..de49969 --- /dev/null +++ b/.cake/Publish-Pack-DotNetCore.cake @@ -0,0 +1,32 @@ +#load "Configuration.cake" + +Task("Publish:Pack:DotNetCore") + .IsDependeeOf("Publish") + .WithCriteria((ctx, config) => config.Solution.NuGetProjects.Any()) + .Does(config => +{ + var projectArtifactDirectory = config.Artifacts.GetRootFor(ArtifactTypeOption.NuGet); + var settings = new DotNetCorePackSettings + { + NoBuild = true, + NoRestore = true, + IncludeSymbols = true, + Configuration = config.Solution.BuildConfiguration, + OutputDirectory = projectArtifactDirectory + }; + settings.MSBuildSettings = new DotNetCoreMSBuildSettings(); + settings.MSBuildSettings + .SetVersion(config.Version.FullSemVersion) + .SetConfiguration(config.Solution.BuildConfiguration) + .WithProperty("PackageVersion", config.Version.SemVersion); + settings.MSBuildSettings.NoLogo = true; + + foreach(var nugetProject in config.Solution.NuGetProjects) { + DotNetCorePack(nugetProject.ProjectFilePath.ToString(), settings); + } + + foreach(var package in GetFiles($"{projectArtifactDirectory}/*.nupkg")) + { + config.Artifacts.Add(ArtifactTypeOption.NuGet, package.GetFilename().ToString(), package.FullPath); + } +}); diff --git a/.cake/Publish-Pack-NuGet.cake b/.cake/Publish-Pack-NuGet.cake new file mode 100644 index 0000000..8ff72fc --- /dev/null +++ b/.cake/Publish-Pack-NuGet.cake @@ -0,0 +1,23 @@ +#load "Configuration.cake" + +Task("Publish:Pack:NuGet") + .IsDependeeOf("Publish") + .WithCriteria((ctx, config) => config.Solution.NuGetProjects.Any()) + .Does(config => +{ + var projectArtifactDirectory = config.Artifacts.GetRootFor(ArtifactTypeOption.NuGet); + + foreach(var nugetProject in config.Solution.NuGetProjects) { + var nuGetPackSettings = new NuGetPackSettings { + Version = $"{config.Version.SemVersion}", + OutputDirectory = $"{projectArtifactDirectory}/" + }; + + NuGetPack(nugetProject.ProjectFilePath.ToString(), nuGetPackSettings); + } + + foreach(var package in GetFiles($"{projectArtifactDirectory}/*.nupkg")) + { + config.Artifacts.Add(ArtifactTypeOption.NuGet, package.GetFilename().ToString(), package.FullPath); + } +}); diff --git a/.cake/Publish-Zip-DotNetCore.cake b/.cake/Publish-Zip-DotNetCore.cake new file mode 100644 index 0000000..87a6eb9 --- /dev/null +++ b/.cake/Publish-Zip-DotNetCore.cake @@ -0,0 +1,32 @@ +#load "Configuration.cake" + +Task("Publish:Zip:DotNetCore") + .IsDependeeOf("Publish") + .WithCriteria((ctx, config) => config.Solution.WebProjects.Any()) + .Does(config => +{ + foreach(var webProject in config.Solution.WebProjects) { + var assemblyName = config.Solution.GetProjectName(webProject); + var projectArtifactDirectory = config.Artifacts.GetRootFor(ArtifactTypeOption.Zip); + var publishDirectory = $"{projectArtifactDirectory}/build/{assemblyName}/"; + var artifactZipName = $"{assemblyName}.zip"; + var artifactZipFullPath = $"{projectArtifactDirectory}/{artifactZipName}"; + + EnsureDirectoryExists(publishDirectory); + + var settings = new DotNetCorePublishSettings + { + NoRestore = true, + Configuration = config.Solution.BuildConfiguration, + OutputDirectory = publishDirectory, + Verbosity = DotNetCoreVerbosity.Minimal, + }; + + settings.MSBuildSettings = new DotNetCoreMSBuildSettings(); + settings.MSBuildSettings.NoLogo = true; + + DotNetCorePublish(webProject.ProjectFilePath.ToString(), settings); + Zip(publishDirectory, artifactZipFullPath); + config.Artifacts.Add(ArtifactTypeOption.Zip, artifactZipName, artifactZipFullPath); + } +}); \ No newline at end of file diff --git a/.cake/Publish-Zip-MsBuild.cake b/.cake/Publish-Zip-MsBuild.cake new file mode 100644 index 0000000..8a7c44c --- /dev/null +++ b/.cake/Publish-Zip-MsBuild.cake @@ -0,0 +1,28 @@ +#load "Configuration.cake" + +Task("Publish:Zip:MsBuild") + .Description("Creates a zip archive from each found project") + .IsDependeeOf("Publish") + .WithCriteria((ctx, config) => config.Solution.LibraryProjects.Any()) + .Does(config => +{ + foreach(var project in config.Solution.LibraryProjects) { + var assemblyName = config.Solution.GetProjectName(project); + var projectArtifactDirectory = config.Artifacts.GetRootFor(ArtifactTypeOption.Zip); + var publishDirectory = project.OutputPaths.FirstOrDefault(); + var artifactZipName = $"{assemblyName}.zip"; + var artifactZipFullPath = $"{projectArtifactDirectory}/{artifactZipName}"; + + if(DirectoryExists(publishDirectory)) + { + Information($"Publishing {assemblyName} from {publishDirectory} to {artifactZipFullPath}"); + + Zip(publishDirectory, artifactZipFullPath); + config.Artifacts.Add(ArtifactTypeOption.Zip, artifactZipName, artifactZipFullPath); + } + else + { + Warning($"Unable to find anything to publish for {assemblyName}"); + } + } +}); diff --git a/.cake/Restore-DotNetCore.cake b/.cake/Restore-DotNetCore.cake new file mode 100644 index 0000000..6fb2bbd --- /dev/null +++ b/.cake/Restore-DotNetCore.cake @@ -0,0 +1,5 @@ +#load "Configuration.cake" + +Task("Restore:DotNetCore") + .IsDependeeOf("Restore") + .Does(config => DotNetCoreRestore(config.Solution.Path.ToString(), new DotNetCoreRestoreSettings { Verbosity = DotNetCoreVerbosity.Minimal })); \ No newline at end of file diff --git a/.cake/Restore-NuGet.cake b/.cake/Restore-NuGet.cake new file mode 100644 index 0000000..9a07f67 --- /dev/null +++ b/.cake/Restore-NuGet.cake @@ -0,0 +1,8 @@ +#load "Configuration.cake" + +Task("Restore:NuGet") + .IsDependeeOf("Restore") + .Does(config => +{ + NuGetRestore(config.Solution.Path.ToString(), new NuGetRestoreSettings()); +}); \ No newline at end of file diff --git a/.cake/Test-DotNetCore.cake b/.cake/Test-DotNetCore.cake new file mode 100644 index 0000000..fe7cab2 --- /dev/null +++ b/.cake/Test-DotNetCore.cake @@ -0,0 +1,52 @@ +#load "Configuration.cake" + +Task("Test:DotNetCore") + .IsDependentOn("Build") + .IsDependeeOf("Test") + .WithCriteria((ctx, config) => config.Solution.TestProjects.Any(p => p.IsDotNetCliTestProject())) + .Does(config => +{ + CreateDirectory($"{config.Artifacts.Root}/test-results"); + var testResultsRoot = $"{config.Artifacts.Root}/test-results"; + + var shouldFail = false; + foreach(var testProject in config.Solution.TestProjects.Where(p => p.IsDotNetCliTestProject())) { + var assemblyName = config.Solution.GetProjectName(testProject); + var testResultsXml = $"{testResultsRoot}/{assemblyName}.xml"; + try + { + var settings = new DotNetCoreTestSettings() { + Configuration = config.Solution.BuildConfiguration, + Logger = $"trx;LogFileName={testResultsXml}", + NoBuild = true, + NoRestore = true + }; + + DotNetCoreTest(testProject.ProjectFilePath.ToString(), settings); + } + catch + { + shouldFail = true; + } + } + + Information("Publishing Test results from {0}", testResultsRoot); + var testResults = GetFiles($"{testResultsRoot}/**/*.xml").ToArray(); + if(testResults.Any()) + { + if(BuildSystem.IsRunningOnAzurePipelinesHosted || TFBuild.IsRunningOnAzurePipelines) + { + TFBuild.Commands.PublishTestResults(new TFBuildPublishTestResultsData() { + Configuration = config.Solution.BuildConfiguration, + MergeTestResults = true, + TestResultsFiles = testResults, + TestRunner = TFTestRunnerType.VSTest + }); + } + } + + if(shouldFail) + { + throw new Exception("Tests have failed"); + } +}); diff --git a/.cake/Test-NUnit2.cake b/.cake/Test-NUnit2.cake new file mode 100644 index 0000000..5ac2e98 --- /dev/null +++ b/.cake/Test-NUnit2.cake @@ -0,0 +1,54 @@ +#tool "nuget:?package=NUnit.Runners&version=2.6.4" +#load "Configuration.cake" + +Task("Test:NUnit") + .IsDependentOn("Build") + .IsDependeeOf("Test") + .WithCriteria((ctx, config) => config.Solution.TestProjects.Any(p => p.IsNUnitTestProject())) + .Does(config => +{ + CreateDirectory($"{config.Artifacts.Root}/test-results"); + + var shouldFail = false; + foreach(var testProject in config.Solution.TestProjects.Where(p => p.IsNUnitTestProject())) { + var assemblyName = config.Solution.GetProjectName(testProject); + var testResultsRoot = $"{config.Artifacts.Root}/test-results"; + var testResultsXml = $"{testResultsRoot}/{assemblyName}.xml"; + var testAssembly = $"{testProject.OutputPaths.FirstOrDefault().ToString()}/{assemblyName}.dll"; + + try + { + var settings = new NUnitSettings() { + NoLogo = true, + ResultsFile = testResultsXml, + OutputFile = $"{testResultsRoot}/{assemblyName}.log", + }; + + NUnit(testAssembly, settings); + } + catch + { + shouldFail = true; + } + } + + Information("Publishing Test results from {0}", config.Artifacts.Root); + var testResults = GetFiles($"{config.Artifacts.Root}/test-results/**/*.xml").ToArray(); + if(testResults.Any()) + { + if(BuildSystem.IsRunningOnAzurePipelinesHosted || TFBuild.IsRunningOnAzurePipelines) + { + TFBuild.Commands.PublishTestResults(new TFBuildPublishTestResultsData() { + Configuration = config.Solution.BuildConfiguration, + MergeTestResults = true, + TestResultsFiles = testResults, + TestRunner = TFTestRunnerType.VSTest + }); + } + } + + if(shouldFail) + { + throw new Exception("Tests have failed"); + } +}); diff --git a/.cake/Test-NUnit3.cake b/.cake/Test-NUnit3.cake new file mode 100644 index 0000000..57e54c4 --- /dev/null +++ b/.cake/Test-NUnit3.cake @@ -0,0 +1,58 @@ +#tool "nuget:?package=NUnit.ConsoleRunner&version=3.10.0" + +#load "Configuration.cake" + +Task("Test:NUnit") + .IsDependentOn("Build") + .IsDependeeOf("Test") + .WithCriteria((ctx, config) => config.Solution.TestProjects.Any(p => p.IsNUnitTestProject())) + .Does(config => +{ + CreateDirectory($"{config.Artifacts.Root}/test-results"); + + var shouldFail = false; + foreach(var testProject in config.Solution.TestProjects.Where(p => p.IsNUnitTestProject())) { + var assemblyName = config.Solution.GetProjectName(testProject); + var testResultsRoot = $"{config.Artifacts.Root}/test-results"; + var testResultsXml = $"{testResultsRoot}/{assemblyName}.xml"; + var testAssembly = $"{testProject.OutputPaths.FirstOrDefault().ToString()}/{assemblyName}.dll"; + + try + { + var settings = new NUnit3Settings() { + NoHeader = true, + Configuration = config.Solution.BuildConfiguration, + Results = new[] { + new NUnit3Result { FileName = testResultsXml } + }, + OutputFile = $"{testResultsRoot}/{assemblyName}.log", + }; + + NUnit3(testAssembly, settings); + } + catch + { + shouldFail = true; + } + } + + Information("Publishing Test results from {0}", config.Artifacts.Root); + var testResults = GetFiles($"{config.Artifacts.Root}/test-results/**/*.xml").ToArray(); + if(testResults.Any()) + { + if(BuildSystem.IsRunningOnAzurePipelinesHosted || TFBuild.IsRunningOnAzurePipelines) + { + TFBuild.Commands.PublishTestResults(new TFBuildPublishTestResultsData() { + Configuration = config.Solution.BuildConfiguration, + MergeTestResults = true, + TestResultsFiles = testResults, + TestRunner = TFTestRunnerType.VSTest + }); + } + } + + if(shouldFail) + { + throw new Exception("Tests have failed"); + } +}); diff --git a/.cake/Test-XUnit2.cake b/.cake/Test-XUnit2.cake new file mode 100644 index 0000000..d3f9d6d --- /dev/null +++ b/.cake/Test-XUnit2.cake @@ -0,0 +1,52 @@ +#tool "xunit.runner.console&version=2.4.1" +#load "Configuration.cake" + +Task("Test:XUnit2") + .IsDependentOn("Build") + .IsDependeeOf("Test") + .WithCriteria((ctx, config) => config.Solution.TestProjects.Any(p => p.IsXUnitTestProject())) + .Does(config => +{ + CreateDirectory($"{config.Artifacts.Root}/test-results"); + + var shouldFail = false; + foreach(var testProject in config.Solution.TestProjects.Where(p => p.IsXUnitTestProject())) { + var assemblyName = config.Solution.GetProjectName(testProject); + var testResultsRoot = $"{config.Artifacts.Root}/test-results"; + var testResultsXml = $"{testResultsRoot}/{assemblyName}.xml"; + try + { + var settings = new XUnit2Settings { + XmlReport = true, + ReportName = assemblyName, + OutputDirectory = $"{testResultsRoot}", + }; + + XUnit2(testAssembly, settings); + } + catch + { + shouldFail = true; + } + } + + Information("Publishing Test results from {0}", config.Artifacts.Root); + var testResults = GetFiles($"{config.Artifacts.Root}/test-results/**/*.xml").ToArray(); + if(testResults.Any()) + { + if(BuildSystem.IsRunningOnAzurePipelinesHosted || TFBuild.IsRunningOnAzurePipelines) + { + TFBuild.Commands.PublishTestResults(new TFBuildPublishTestResultsData() { + Configuration = config.Solution.BuildConfiguration, + MergeTestResults = true, + TestResultsFiles = testResults, + TestRunner = TFTestRunnerType.VSTest + }); + } + } + + if(shouldFail) + { + throw new Exception("Tests have failed"); + } +}); diff --git a/.gitignore b/.gitignore index c397259..52a02fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,10 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. - -# Build related -/tools/ -!/tools/packages.config - -/VersionAssemblyInfo.cs -/artifacts/ +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files +*.rsuser *.suo *.user *.userosscache @@ -17,6 +13,9 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs +# Mono auto generated files +mono_crash.* + # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -24,35 +23,58 @@ [Rr]eleases/ x64/ x86/ -build/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ +[Ll]og/ +[Ll]ogs/ -# Visual Studo 2015 cache/options directory +# Visual Studio 2015/2017 cache/options directory .vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUNIT +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -62,6 +84,7 @@ dlldata.c *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log *.vspscc *.vssscc @@ -77,14 +100,21 @@ _Chutzpah* ipch/ *.aps *.ncb +*.opendb *.opensdf *.sdf *.cachefile +*.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx +*.sap + +# Visual Studio Trace Files +*.e2e # TFS 2012 Local Workspace $tf/ @@ -97,7 +127,7 @@ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user -# JustCode is a .NET coding addin-in +# JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in @@ -106,9 +136,18 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml +nCrunchTemp_* # MightyMoose *.mm.* @@ -136,39 +175,71 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings +# Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + # NuGet Packages *.nupkg +# NuGet Symbol Packages +*.snupkg # The packages folder can be ignored because of Package Restore -**/packages/* +**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/packages/build/ +!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets -# Windows Azure Build Output +# Microsoft Azure Build Output csx/ *.build.csdef -# Windows Store app package directory +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ # Others -*.[Cc]ache ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm *.pfx *.publishsettings -node_modules/ -bower_components/ +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ # RIA/Silverlight projects Generated_Code/ @@ -180,24 +251,106 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ +# GhostDoc plugin setting file +*.GhostDoc.xml + # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +tools/** +!tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +/artifacts +/VersionAssemblyInfo.cs \ No newline at end of file diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000..a38f077 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,22 @@ +assembly-versioning-scheme: MajorMinorPatchTag +assembly-file-versioning-scheme: MajorMinorPatchTag +assembly-informational-format: '{MajorMinorPatch}+{BranchName}+{CommitDate}' +mode: Mainline +continuous-delivery-fallback-tag: +branches: + release: + mode: ContinuousDelivery + tag: '' + master: + tag: ci + pull-request: + mode: ContinuousDeployment + tag: pr + hotfix: + mode: ContinuousDeployment + tag: fix + feature: + mode: ContinuousDeployment + tag: wip +ignore: + sha: [] diff --git a/GitVersionConfig.yaml b/GitVersionConfig.yaml deleted file mode 100644 index a9ea335..0000000 --- a/GitVersionConfig.yaml +++ /dev/null @@ -1,12 +0,0 @@ -assembly-versioning-scheme: MajorMinorPatch -mode: ContinuousDeployment -continuous-delivery-fallback-tag: preview -branches: - master: - increment: Patch - prevent-increment-of-merged-branch-version: true - (pull|pull\-requests|pr)[/-]: - tag: PullRequest - increment: Inherit - track-merge-target: true - tag-number-pattern: '[/-](?\d+)[-/]' \ No newline at end of file diff --git a/Nest.Queryify.sln b/Nest.Queryify.sln index 56d82d7..e0aae10 100644 --- a/Nest.Queryify.sln +++ b/Nest.Queryify.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.12 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29318.209 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nest.Queryify", "src\Nest.Queryify\Nest.Queryify.csproj", "{70F41783-BD20-4C56-941A-E370ED41D397}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nest.Queryify", "src\Nest.Queryify\Nest.Queryify.csproj", "{70F41783-BD20-4C56-941A-E370ED41D397}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4F70AD04-ACBB-45A8-9361-B240FDAA6154}" EndProject @@ -33,4 +33,7 @@ Global {70F41783-BD20-4C56-941A-E370ED41D397} = {4F70AD04-ACBB-45A8-9361-B240FDAA6154} {641A95FD-C70B-4925-AD19-EC410E52BF6F} = {B851DD22-E4FB-4F42-9579-21FEDBAD11BD} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {664DB264-C1D7-4060-8A9B-36D454900897} + EndGlobalSection EndGlobal diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index cea7a55..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: '{build}' -os: Visual Studio 2017 -init: -- cmd: git config --global core.autocrlf true -build_script: -- ps: .\build.ps1 -Target "CI" -Verbosity "Normal" -Configuration "Release" -test: off -deploy: -- provider: Environment - name: MyGet (ES Snapback) - on: - branch: /release\/.+/ \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..5dcfda4 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,101 @@ +trigger: + batch: true + branches: + include: + - master + - release/* +variables: + vmImage: 'windows-latest' +stages: +- stage: build + displayName: 'Build' + jobs: + - job: cake + displayName: 'Cake' + pool: + vmImage: $(vmImage) + variables: + cake.buildTarget: 'CI' + build.configuration: 'Release' + cake.verbosity: 'Verbose' + steps: + - powershell: ./build.ps1 -Target "$(cake.buildTarget)" -Configuration "$(build.configuration)" -Verbosity "$(cake.verbosity)" + displayName: 'Cake Build' + + - powershell: Write-Host '##vso[build.addbuildtag]PR' + displayName: 'Mark as PR Build' + condition: and(succeeded(), in(variables['Build.Reason'], 'PullRequest')) + + - powershell: Write-Host '##vso[build.addbuildtag]Release' + displayName: 'Mark as Release Build' + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')) + +- stage: 'PublishCI' + displayName: 'Publish CI' + dependsOn: build + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/master')) + jobs: + - job: PublishInternal + displayName: 'Publish to Artifacts' + pool: + vmImage: $(vmImage) + steps: + - task: DownloadBuildArtifacts@0 + inputs: + buildType: 'current' + downloadType: 'specific' + itemPattern: '**' + downloadPath: '$(System.ArtifactsDirectory)' + - task: NuGetCommand@2 + inputs: + command: 'push' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: '$(artifacts.ci.feed)' + allowPackageConflicts: true + +- stage: PublishPreview + displayName: 'Publish Preview' + dependsOn: build + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')) + jobs: + - job: PublishInternal + displayName: 'Publish to Artifacts' + pool: + vmImage: $(vmImage) + steps: + - task: DownloadBuildArtifacts@0 + inputs: + buildType: 'current' + downloadType: 'specific' + itemPattern: '**' + downloadPath: '$(System.ArtifactsDirectory)' + - task: NuGetCommand@2 + inputs: + command: 'push' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'internal' + publishVstsFeed: '$(artifacts.preview.feed)' + allowPackageConflicts: true +- stage: PublishRelease + displayName: 'Publish Release' + dependsOn: build + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/')) + jobs: + - job: PublishNuGet + displayName: 'Publish to NuGet' + pool: + vmImage: $(vmImage) + steps: + - task: DownloadBuildArtifacts@0 + inputs: + buildType: 'current' + downloadType: 'specific' + itemPattern: '**' + downloadPath: '$(System.ArtifactsDirectory)' + - task: NuGetCommand@2 + inputs: + command: 'push' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' + nuGetFeedType: 'external' + publishFeedCredentials: '$(artifacts.nuget.feed)' \ No newline at end of file diff --git a/build.cake b/build.cake index d9023c8..4a81978 100644 --- a/build.cake +++ b/build.cake @@ -1,230 +1,16 @@ -#tool "GitVersion.CommandLine" +#load ".cake/Configuration.cake" -////////////////////////////////////////////////////////////////////// -// ARGUMENTS -////////////////////////////////////////////////////////////////////// +/**********************************************************/ +Setup(Configuration.Create); +/**********************************************************/ -var target = Argument("target", AppVeyor.IsRunningOnAppVeyor ? "CI" : "Default"); -var configuration = Argument("configuration", "Release"); -var solutionPath = MakeAbsolute(File(Argument("solutionPath", "./Nest.Queryify.sln"))); +#load ".cake/CI.cake" -////////////////////////////////////////////////////////////////////// -// PREPARATION -////////////////////////////////////////////////////////////////////// +// -- DotNetCore +#load ".cake/Restore-DotNetCore.cake" +#load ".cake/Build-DotNetCore.cake" +#load ".cake/Test-DotNetCore.cake" +#load ".cake/Publish-Pack-DotNetCore.cake" +// ------------- -var testAssemblies = "./tests/**/bin/" +configuration +"/*.Tests.dll"; -var coverageReportXmlFilePath = ""; - -var artifacts = MakeAbsolute(Directory(Argument("artifactPath", "./artifacts"))); -var versionAssemblyInfo = MakeAbsolute(File(Argument("versionAssemblyInfo", "VersionAssemblyInfo.cs"))); - -IEnumerable nugetProjectPaths = null; -SolutionParserResult solution = null; -GitVersion versionInfo = null; - -////////////////////////////////////////////////////////////////////// -// TASKS -////////////////////////////////////////////////////////////////////// - -Setup(ctx => { - if(!FileExists(solutionPath)) throw new Exception(string.Format("Solution file not found - {0}", solutionPath.ToString())); - solution = ParseSolution(solutionPath.ToString()); - - Information("[Setup] Using Solution '{0}'", solutionPath.ToString()); - - if(DirectoryExists(artifacts)) - { - DeleteDirectory(artifacts, true); - } - - EnsureDirectoryExists(artifacts); - - var binDirs = GetDirectories(solutionPath.GetDirectory() +@"\src\**\bin"); - var objDirs = GetDirectories(solutionPath.GetDirectory() +@"\src\**\obj"); - DeleteDirectories(binDirs, true); - DeleteDirectories(objDirs, true); -}); - -Task("Update-Version-Info") - .IsDependentOn("CreateVersionAssemblyInfo") - .Does(() => -{ - versionInfo = GitVersion(new GitVersionSettings { - UpdateAssemblyInfo = true, - UpdateAssemblyInfoFilePath = versionAssemblyInfo - }); - - if(versionInfo != null) { - Information("Version: {0}", versionInfo.FullSemVer); - } else { - throw new Exception("Unable to determine version"); - } -}); - -Task("CreateVersionAssemblyInfo") - .WithCriteria(() => !FileExists(versionAssemblyInfo)) - .Does(() => -{ - Information("Creating version assembly info"); - CreateAssemblyInfo(versionAssemblyInfo, new AssemblyInfoSettings { - Version = "0.0.0.0", - FileVersion = "0.0.0.0", - InformationalVersion = "", - }); -}); - -Task("DotNet-MsBuild-Restore") - .IsDependentOn("Update-Version-Info") - .Does(() => { - - MSBuild(solutionPath, c => c - .SetConfiguration(configuration) - .SetVerbosity(Verbosity.Minimal) - .UseToolVersion(MSBuildToolVersion.VS2017) - .WithTarget("Restore") - ); -}); - -Task("DotNet-MsBuild") - .IsDependentOn("Restore") - .Does(() => { - - MSBuild(solutionPath, c => c - .SetConfiguration(configuration) - .SetVerbosity(Verbosity.Minimal) - .UseToolVersion(MSBuildToolVersion.VS2017) - .WithProperty("TreatWarningsAsErrors", "true") - .WithTarget("Build") - ); - -}); - -Task("DotNet-MsBuild-Pack") - .IsDependentOn("Build") - .Does(() => { - - MSBuild("src/Nest.Queryify/Nest.Queryify.csproj", c => c - .SetConfiguration(configuration) - .SetVerbosity(Verbosity.Normal) - .UseToolVersion(MSBuildToolVersion.VS2017) - .WithProperty("PackageVersion", versionInfo.NuGetVersionV2) - .WithProperty("NoBuild", "true") - .WithTarget("Pack") - ); -}); - -Task("DotNet-MsBuild-CopyToArtifacts") - .IsDependentOn("DotNet-MsBuild-Pack") - .Does(() => { - - EnsureDirectoryExists(artifacts); - CopyFiles("src/Nest.Queryify/bin/" +configuration +"/*.nupkg", artifacts); -}); - -Task("DotNet-Test") - .IsDependentOn("Build") - .Does(() => { - - var settings = new DotNetCoreTestSettings - { - Configuration = configuration, - NoBuild = true - }; - - DotNetCoreTest("tests/Nest.Queryify.Tests/Nest.Queryify.Tests.csproj", settings); -}); - -Task("Print-AppVeyor-Environment-Variables") - .WithCriteria(AppVeyor.IsRunningOnAppVeyor) - .Does(() => -{ - Information("CI: {0}", EnvironmentVariable("CI")); - Information("APPVEYOR_API_URL: {0}", EnvironmentVariable("APPVEYOR_API_URL")); - Information("APPVEYOR_PROJECT_ID: {0}", EnvironmentVariable("APPVEYOR_PROJECT_ID")); - Information("APPVEYOR_PROJECT_NAME: {0}", EnvironmentVariable("APPVEYOR_PROJECT_NAME")); - Information("APPVEYOR_PROJECT_SLUG: {0}", EnvironmentVariable("APPVEYOR_PROJECT_SLUG")); - Information("APPVEYOR_BUILD_FOLDER: {0}", EnvironmentVariable("APPVEYOR_BUILD_FOLDER")); - Information("APPVEYOR_BUILD_ID: {0}", EnvironmentVariable("APPVEYOR_BUILD_ID")); - Information("APPVEYOR_BUILD_NUMBER: {0}", EnvironmentVariable("APPVEYOR_BUILD_NUMBER")); - Information("APPVEYOR_BUILD_VERSION: {0}", EnvironmentVariable("APPVEYOR_BUILD_VERSION")); - Information("APPVEYOR_PULL_REQUEST_NUMBER: {0}", EnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER")); - Information("APPVEYOR_PULL_REQUEST_TITLE: {0}", EnvironmentVariable("APPVEYOR_PULL_REQUEST_TITLE")); - Information("APPVEYOR_JOB_ID: {0}", EnvironmentVariable("APPVEYOR_JOB_ID")); - Information("APPVEYOR_REPO_PROVIDER: {0}", EnvironmentVariable("APPVEYOR_REPO_PROVIDER")); - Information("APPVEYOR_REPO_SCM: {0}", EnvironmentVariable("APPVEYOR_REPO_SCM")); - Information("APPVEYOR_REPO_NAME: {0}", EnvironmentVariable("APPVEYOR_REPO_NAME")); - Information("APPVEYOR_REPO_BRANCH: {0}", EnvironmentVariable("APPVEYOR_REPO_BRANCH")); - Information("APPVEYOR_REPO_TAG: {0}", EnvironmentVariable("APPVEYOR_REPO_TAG")); - Information("APPVEYOR_REPO_TAG_NAME: {0}", EnvironmentVariable("APPVEYOR_REPO_TAG_NAME")); - Information("APPVEYOR_REPO_COMMIT: {0}", EnvironmentVariable("APPVEYOR_REPO_COMMIT")); - Information("APPVEYOR_REPO_COMMIT_AUTHOR: {0}", EnvironmentVariable("APPVEYOR_REPO_COMMIT_AUTHOR")); - Information("APPVEYOR_REPO_COMMIT_TIMESTAMP: {0}", EnvironmentVariable("APPVEYOR_REPO_COMMIT_TIMESTAMP")); - Information("APPVEYOR_SCHEDULED_BUILD: {0}", EnvironmentVariable("APPVEYOR_SCHEDULED_BUILD")); - Information("APPVEYOR_FORCED_BUILD: {0}", EnvironmentVariable("APPVEYOR_FORCED_BUILD")); - Information("APPVEYOR_RE_BUILD: {0}", EnvironmentVariable("APPVEYOR_RE_BUILD")); - Information("PLATFORM: {0}", EnvironmentVariable("PLATFORM")); - Information("CONFIGURATION: {0}", EnvironmentVariable("CONFIGURATION")); - -}); - -Task("AppVeyor-Update-Build-Number") - .IsDependentOn("Update-Version-Info") - .WithCriteria(() => AppVeyor.IsRunningOnAppVeyor) - .Does(() => -{ - AppVeyor.UpdateBuildVersion(versionInfo.FullSemVer +"|" +AppVeyor.Environment.Build.Number); -}); - -Task("Appveyor-Upload-Artifacts") - .IsDependentOn("Package") - .WithCriteria(() => AppVeyor.IsRunningOnAppVeyor) - .Does(() => -{ - foreach(var nupkg in GetFiles(artifacts +"/*.nupkg")) { - AppVeyor.UploadArtifact(nupkg); - } -}); - -Task("Appveyor") - .WithCriteria(() => AppVeyor.IsRunningOnAppVeyor) - .IsDependentOn("Print-AppVeyor-Environment-Variables") - .IsDependentOn("AppVeyor-Update-Build-Number") - .IsDependentOn("AppVeyor-Upload-Artifacts"); - -// ************************** // - -Task("Restore") - .IsDependentOn("DotNet-MsBuild-Restore"); - -Task("Build") - .IsDependentOn("Restore") - .IsDependentOn("DotNet-MsBuild"); - -Task("Test") - .IsDependentOn("Build") - .IsDependentOn("DotNet-Test"); - -Task("Package") - .IsDependentOn("Build") - .IsDependentOn("DotNet-MsBuild-CopyToArtifacts") - .IsDependentOn("DotNet-MsBuild-Pack"); - -Task("CI") - .IsDependentOn("AppVeyor") - .IsDependentOn("Default"); - -////////////////////////////////////////////////////////////////////// -// TASK TARGETS -////////////////////////////////////////////////////////////////////// - -Task("Default") - .IsDependentOn("Restore") - .IsDependentOn("Build") - .IsDependentOn("Test") - .IsDependentOn("Package"); - -////////////////////////////////////////////////////////////////////// -// EXECUTION -////////////////////////////////////////////////////////////////////// - -RunTarget(target); +RunTarget(Argument("target", Argument("Target", "Default"))); \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 18b8560..82529cf 100644 --- a/build.ps1 +++ b/build.ps1 @@ -21,68 +21,92 @@ The build script target to run. The build configuration to use. .PARAMETER Verbosity Specifies the amount of information to be displayed. +.PARAMETER ShowDescription +Shows description about tasks. +.PARAMETER DryRun +Performs a dry run. .PARAMETER Experimental -Tells Cake to use the latest Roslyn release. -.PARAMETER WhatIf -Performs a dry run of the build script. -No tasks will be executed. +Uses the nightly builds of the Roslyn script engine. .PARAMETER Mono -Tells Cake to use the Mono scripting engine. +Uses the Mono Compiler rather than the Roslyn script engine. .PARAMETER SkipToolPackageRestore Skips restoring of packages. .PARAMETER ScriptArgs Remaining arguments are added here. .LINK -http://cakebuild.net +https://cakebuild.net #> [CmdletBinding()] Param( [string]$Script = "build.cake", - [string]$Target = "Default", - [string]$Configuration = "Release", + [string]$Target, + [string]$Configuration, [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity = "Verbose", + [string]$Verbosity, + [switch]$ShowDescription, + [Alias("WhatIf", "Noop")] + [switch]$DryRun, [switch]$Experimental, - [Alias("DryRun","Noop")] - [switch]$WhatIf, [switch]$Mono, [switch]$SkipToolPackageRestore, [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] [string[]]$ScriptArgs ) -Write-Host "Preparing to run build script..." - -$PSScriptRoot = split-path -parent $MyInvocation.MyCommand.Definition; -$TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$NUGET_URL = "http://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } -# Should we use mono? -$UseMono = ""; -if($Mono.IsPresent) { - Write-Verbose -Message "Using the Mono based scripting engine." - $UseMono = "-mono" + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } } -# Should we use the new Roslyn? -$UseExperimental = ""; -if($Experimental.IsPresent -and !($Mono.IsPresent)) { - Write-Verbose -Message "Using experimental version of Roslyn." - $UseExperimental = "-experimental" +function GetProxyEnabledWebClient +{ + $wc = New-Object System.Net.WebClient + $proxy = [System.Net.WebRequest]::GetSystemWebProxy() + $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials + $wc.Proxy = $proxy + return $wc } -# Is this a dry run? -$UseDryRun = ""; -if($WhatIf.IsPresent) { - $UseDryRun = "-dryrun" +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" +$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" +$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" +$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" + # Make sure tools folder exists if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { Write-Verbose -Message "Creating tools directory..." @@ -91,8 +115,10 @@ if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { # Make sure that packages.config exist. if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { Invoke-WebRequest -Uri http://cakebuild.net/download/bootstrapper/packages -OutFile $PACKAGES_CONFIG } catch { + Write-Verbose -Message "Downloading packages.config..." + try { + $wc = GetProxyEnabledWebClient + $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { Throw "Could not download packages.config." } } @@ -100,7 +126,7 @@ if (!(Test-Path $PACKAGES_CONFIG)) { # Try find NuGet.exe in path if not exists if (!(Test-Path $NUGET_EXE)) { Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." @@ -112,7 +138,8 @@ if (!(Test-Path $NUGET_EXE)) { if (!(Test-Path $NUGET_EXE)) { Write-Verbose -Message "Downloading NuGet.exe..." try { - (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + $wc = GetProxyEnabledWebClient + $wc.DownloadFile($NUGET_URL, $NUGET_EXE) } catch { Throw "Could not download NuGet.exe." } @@ -125,12 +152,62 @@ $ENV:NUGET_EXE = $NUGET_EXE if(-Not $SkipToolPackageRestore.IsPresent) { Push-Location Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | + Remove-Item -Recurse + } + Write-Verbose -Message "Restoring tools from NuGet..." $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" + if ($LASTEXITCODE -ne 0) { - Throw "An error occured while restoring NuGet tools." + Throw "An error occurred while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" } Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore addins from NuGet +if (Test-Path $ADDINS_PACKAGES_CONFIG) { + Push-Location + Set-Location $ADDINS_DIR + + Write-Verbose -Message "Restoring addins from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occurred while restoring NuGet addins." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + + Pop-Location +} + +# Restore modules from NuGet +if (Test-Path $MODULES_PACKAGES_CONFIG) { + Push-Location + Set-Location $MODULES_DIR + + Write-Verbose -Message "Restoring modules from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occurred while restoring NuGet modules." + } + + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location } @@ -139,7 +216,20 @@ if (!(Test-Path $CAKE_EXE)) { Throw "Could not find Cake.exe at $CAKE_EXE" } + + +# Build Cake arguments +$cakeArguments = @("$Script"); +if ($Target) { $cakeArguments += "-target=$Target" } +if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } +if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } +if ($ShowDescription) { $cakeArguments += "-showdescription" } +if ($DryRun) { $cakeArguments += "-dryrun" } +if ($Experimental) { $cakeArguments += "-experimental" } +if ($Mono) { $cakeArguments += "-mono" } +$cakeArguments += $ScriptArgs + # Start Cake Write-Host "Running build script..." -Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" +&$CAKE_EXE $cakeArguments exit $LASTEXITCODE diff --git a/src/Nest.Queryify/Nest.Queryify.csproj b/src/Nest.Queryify/Nest.Queryify.csproj index 1e1625f..f0c4de9 100644 --- a/src/Nest.Queryify/Nest.Queryify.csproj +++ b/src/Nest.Queryify/Nest.Queryify.csproj @@ -1,10 +1,9 @@  - net45;net46;netstandard1.6 + net461;netstandard2.0 Nest.Queryify Nest.Queryify - $(PackageTargetFallback);dnxcore50 - 1.6.0 + 2.0 false false false @@ -18,21 +17,22 @@ Storm ID Use a query object design pattern to write elasticsearch commands. Phil Oyston, Storm ID Ltd. - https://www.stormid.com/content/img/icons/apple-touch-icon.png + https://www.stormid.com/content/img/icons/apple-touch-icon.png https://github.com/stormid/Nest-Queryify - https://github.com/stormid/Nest-Queryify/blob/master/LICENSE + MIT elasticsearch nest true False + MIT - + - + diff --git a/tests/Nest.Queryify.Tests/Nest.Queryify.Tests.csproj b/tests/Nest.Queryify.Tests/Nest.Queryify.Tests.csproj index f6e4dd4..3321253 100644 --- a/tests/Nest.Queryify.Tests/Nest.Queryify.Tests.csproj +++ b/tests/Nest.Queryify.Tests/Nest.Queryify.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp1.1;net452;net46 - $(PackageTargetFallback);dnxcore50 + netcoreapp2.0;net461 false false false @@ -26,30 +25,25 @@ - + - - - - - - - - - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - diff --git a/tests/Nest.Queryify.Tests/Queries/Specs/MultiSearchQuerySpecs.cs b/tests/Nest.Queryify.Tests/Queries/Specs/MultiSearchQuerySpecs.cs index 1f69f79..9dac467 100644 --- a/tests/Nest.Queryify.Tests/Queries/Specs/MultiSearchQuerySpecs.cs +++ b/tests/Nest.Queryify.Tests/Queries/Specs/MultiSearchQuerySpecs.cs @@ -23,8 +23,7 @@ public MultiSearchQuerySpecs(ElasticClientQueryObjectTestFixture fixture) : base protected override void AssertExpectations() { Fixture.ShouldUseHttpMethod("POST"); - Fixture.ShouldUseUri(new Uri("http://localhost:9200/_msearch")); - // Fixture.RespondsWith().Should().NotBeNull(); + Fixture.ShouldUseUri(new Uri("http://localhost:9200/_msearch?typed_keys=true")); } protected override ElasticClientQueryObject Query() diff --git a/tests/Nest.Queryify.Tests/Queries/Specs/SearchQuerySpecs.cs b/tests/Nest.Queryify.Tests/Queries/Specs/SearchQuerySpecs.cs index 25f7e51..f4d34a2 100644 --- a/tests/Nest.Queryify.Tests/Queries/Specs/SearchQuerySpecs.cs +++ b/tests/Nest.Queryify.Tests/Queries/Specs/SearchQuerySpecs.cs @@ -22,8 +22,7 @@ public SearchQuerySpecs(ElasticClientQueryObjectTestFixture fixture) : base(fixt protected override void AssertExpectations() { Fixture.ShouldUseHttpMethod("POST"); - Fixture.ShouldUseUri(new Uri("http://localhost:9200/my-application/person/_search")); - // Fixture.RespondsWith>().Should().NotBeNull(); + Fixture.ShouldUseUri(new Uri("http://localhost:9200/my-application/person/_search?typed_keys=true")); } protected override ElasticClientQueryObject> Query() diff --git a/tests/Nest.Queryify.Tests/Queries/Specs/SearchQueryWithReturnDocumentSpecs.cs b/tests/Nest.Queryify.Tests/Queries/Specs/SearchQueryWithReturnDocumentSpecs.cs index 13b1aea..4380d78 100644 --- a/tests/Nest.Queryify.Tests/Queries/Specs/SearchQueryWithReturnDocumentSpecs.cs +++ b/tests/Nest.Queryify.Tests/Queries/Specs/SearchQueryWithReturnDocumentSpecs.cs @@ -22,9 +22,7 @@ public SearchQueryWithReturnDocumentSpecs(ElasticClientQueryObjectTestFixture fi protected override void AssertExpectations() { Fixture.ShouldUseHttpMethod("POST"); - Fixture.ShouldUseUri(new Uri("http://localhost:9200/my-application/person/_search")); - //Fixture.RespondsWith>().Should().NotBeNull(); - //Fixture.RespondsWith>().Documents.Any().Should().BeFalse(); + Fixture.ShouldUseUri(new Uri("http://localhost:9200/my-application/person/_search?typed_keys=true")); } protected override ElasticClientQueryObject> Query() diff --git a/tools/packages.config b/tools/packages.config new file mode 100644 index 0000000..9fc114d --- /dev/null +++ b/tools/packages.config @@ -0,0 +1,4 @@ + + + +