diff --git a/.dependabot/config.yml b/.dependabot/config.yml index eff07b3..66c35db 100644 --- a/.dependabot/config.yml +++ b/.dependabot/config.yml @@ -4,6 +4,15 @@ update_configs: directory: "/" update_schedule: "daily" automerged_updates: + - match: + dependency_name: "ApprovalTests" + update_type: "all" + - match: + dependency_name: "Blorc.*" + update_type: "all" + - match: + dependency_name: "Catel.*" + update_type: "all" - match: dependency_name: "Fody" update_type: "all" @@ -11,7 +20,13 @@ update_configs: dependency_name: "*.Fody" update_type: "all" - match: - dependency_name: "Catel.*" + dependency_name: "Microsoft.*" + update_type: "all" + - match: + dependency_name: "NUnit" + update_type: "all" + - match: + dependency_name: "NUnit3TestAdapter" update_type: "all" - match: dependency_name: "Orc.*" @@ -20,5 +35,5 @@ update_configs: dependency_name: "Orchestra.*" update_type: "all" - match: - dependency_name: "Blorc.*" + dependency_name: "PublicApiGenerator" update_type: "all" \ No newline at end of file diff --git a/.gitignore b/.gitignore index bba8c76..5f95866 100644 --- a/.gitignore +++ b/.gitignore @@ -135,5 +135,12 @@ TestResults .github/ BundleArtifacts/ +# editors +.idea .vscode -FodyWeavers.xsd \ No newline at end of file + +# fody +FodyWeavers.xsd + +# Approval tests +*.received.cs diff --git a/GitVersionConfig.yaml b/GitVersion.yml similarity index 78% rename from GitVersionConfig.yaml rename to GitVersion.yml index af70400..d42e66a 100644 --- a/GitVersionConfig.yaml +++ b/GitVersion.yml @@ -1,3 +1,3 @@ mode: ContinuousDeployment assembly-versioning-scheme: MajorMinorPatch -next-version: 3.0.0 \ No newline at end of file +next-version: 4.0.0 diff --git a/deployment/cake/apps-uwp-tasks.cake b/deployment/cake/apps-uwp-tasks.cake index bd8d6a2..6055134 100644 --- a/deployment/cake/apps-uwp-tasks.cake +++ b/deployment/cake/apps-uwp-tasks.cake @@ -36,7 +36,7 @@ public class UwpProcessor : ProcessorBase private string GetArtifactsDirectory(string outputRootDirectory) { // 1 directory up since we want to turn "/output/release" into "/output/" - var artifactsDirectoryString = string.Format("{0}/..", outputRootDirectory); + var artifactsDirectoryString = System.IO.Path.Combine(outputRootDirectory, ".."); var artifactsDirectory = CakeContext.MakeAbsolute(CakeContext.Directory(artifactsDirectoryString)).FullPath; return artifactsDirectory; @@ -44,7 +44,7 @@ public class UwpProcessor : ProcessorBase private string GetAppxUploadFileName(string artifactsDirectory, string solutionName, string versionMajorMinorPatch) { - var appxUploadSearchPattern = artifactsDirectory + string.Format("/{0}_{1}.0_*.appxupload", solutionName, versionMajorMinorPatch); + var appxUploadSearchPattern = System.IO.Path.Combine(artifactsDirectory, string.Format("{0}_{1}.0_*.appxupload", solutionName, versionMajorMinorPatch)); CakeContext.Information("Searching for appxupload using '{0}'", appxUploadSearchPattern); @@ -89,7 +89,7 @@ public class UwpProcessor : ProcessorBase foreach (var uwpApp in BuildContext.Uwp.Items) { - var appxManifestFile = string.Format("./src/{0}/Package.appxmanifest", uwpApp); + var appxManifestFile = System.IO.Path.Combine(".", "src", uwpApp, "Package.appxmanifest"); UpdateAppxManifestVersion(appxManifestFile, string.Format("{0}.0", BuildContext.General.Version.MajorMinorPatch)); } } diff --git a/deployment/cake/apps-web-tasks.cake b/deployment/cake/apps-web-tasks.cake index 54d8a00..2c25e1b 100644 --- a/deployment/cake/apps-web-tasks.cake +++ b/deployment/cake/apps-web-tasks.cake @@ -91,7 +91,7 @@ public class WebProcessor : ProcessorBase // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which // are properties passed in using the command line) - var outputDirectory = string.Format("{0}/{1}/", BuildContext.General.OutputRootDirectory, webApp); + var outputDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, webApp); CakeContext.Information("Output directory: '{0}'", outputDirectory); msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); @@ -114,11 +114,17 @@ public class WebProcessor : ProcessorBase foreach (var webApp in BuildContext.Web.Items) { + if (!ShouldDeployProject(BuildContext, webApp)) + { + CakeContext.Information("Web app '{0}' should not be deployed", webApp); + continue; + } + BuildContext.CakeContext.LogSeparator("Packaging web app '{0}'", webApp); - var projectFileName = string.Format("./src/{0}/{0}.csproj", webApp); + var projectFileName = System.IO.Path.Combine(".", "src", webApp, $"{webApp}.csproj"); - var outputDirectory = string.Format("{0}/{1}/", BuildContext.General.OutputRootDirectory, webApp); + var outputDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, webApp); CakeContext.Information("Output directory: '{0}'", outputDirectory); CakeContext.Information("1) Using 'dotnet publish' to package '{0}'", webApp); @@ -173,7 +179,7 @@ public class WebProcessor : ProcessorBase BuildContext.CakeContext.LogSeparator("Deploying web app '{0}'", webApp); - var packageToPush = string.Format("{0}/{1}.{2}.nupkg", BuildContext.General.OutputRootDirectory, webApp, BuildContext.General.Version.NuGet); + var packageToPush = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, string.Format("{0}.{1}.nupkg", webApp, BuildContext.General.Version.NuGet)); var octopusRepositoryUrl = BuildContext.OctopusDeploy.GetRepositoryUrl(webApp); var octopusRepositoryApiKey = BuildContext.OctopusDeploy.GetRepositoryApiKey(webApp); var octopusDeploymentTarget = BuildContext.OctopusDeploy.GetDeploymentTarget(webApp); diff --git a/deployment/cake/apps-wpf-tasks.cake b/deployment/cake/apps-wpf-tasks.cake index 90c13ba..0be9b90 100644 --- a/deployment/cake/apps-wpf-tasks.cake +++ b/deployment/cake/apps-wpf-tasks.cake @@ -62,13 +62,13 @@ public class WpfProcessor : ProcessorBase var channelSuffix = BuildContext.Installer.GetDeploymentChannelSuffix(); - var sourceFileName = $"./design/logo/logo{channelSuffix}.ico"; + var sourceFileName = System.IO.Path.Combine(".", "design", "logo", $"logo{channelSuffix}.ico"); if (BuildContext.CakeContext.FileExists(sourceFileName)) { CakeContext.Information("Enforcing channel specific icon '{0}'", sourceFileName); var projectDirectory = GetProjectDirectory(wpfApp); - var targetFileName = $"{projectDirectory}/Resources/Icons/logo.ico"; + var targetFileName = System.IO.Path.Combine(projectDirectory, "Resources", "Icons", "logo.ico"); BuildContext.CakeContext.CopyFile(sourceFileName, targetFileName); } @@ -117,15 +117,12 @@ public class WpfProcessor : ProcessorBase if (BuildContext.General.IsOfficialBuild) { - // All channels - channels.Add("alpha"); - channels.Add("beta"); + // Note: we used to deploy stable to stable, beta and alpha, but want to keep things separated now channels.Add("stable"); } else if (BuildContext.General.IsBetaBuild) { - // Both alpha and beta, since MyApp.beta1 should also be available on the alpha channel - channels.Add("alpha"); + // Note: we used to deploy beta to beta and alpha, but want to keep things separated now channels.Add("beta"); } else if (BuildContext.General.IsAlphaBuild) @@ -143,6 +140,12 @@ public class WpfProcessor : ProcessorBase foreach (var wpfApp in BuildContext.Wpf.Items) { + if (!ShouldDeployProject(BuildContext, wpfApp)) + { + CakeContext.Information("WPF app '{0}' should not be deployed", wpfApp); + continue; + } + CakeContext.Information("Deleting unnecessary files for WPF app '{0}'", wpfApp); var outputDirectory = GetProjectOutputDirectory(BuildContext, wpfApp); @@ -199,7 +202,7 @@ public class WpfProcessor : ProcessorBase BuildContext.CakeContext.LogSeparator("Deploying WPF app '{0}'", wpfApp); //%DeploymentsShare%\%ProjectName% /%ProjectName% -c %AzureDeploymentsStorageConnectionString% - var deploymentShare = string.Format("{0}/{1}", BuildContext.Wpf.DeploymentsShare, wpfApp); + var deploymentShare = System.IO.Path.Combine(BuildContext.Wpf.DeploymentsShare, wpfApp); var exitCode = CakeContext.StartProcess(azureStorageSyncExe, new ProcessSettings { diff --git a/deployment/cake/buildserver.cake b/deployment/cake/buildserver.cake index 0324b48..297ea37 100644 --- a/deployment/cake/buildserver.cake +++ b/deployment/cake/buildserver.cake @@ -135,7 +135,7 @@ public class BuildServerIntegration : IIntegration } } - var overrideFile = "./build.cakeoverrides"; + var overrideFile = System.IO.Path.Combine(".", "build.cakeoverrides"); if (System.IO.File.Exists(overrideFile)) { var sb = new StringBuilder(string.Empty, 256); @@ -144,7 +144,14 @@ public class BuildServerIntegration : IIntegration { CakeContext.Information("Variable '{0}' is specified via build.cakeoverrides", variableName); - return sb.ToString(); + var sbValue = sb.ToString(); + if (sbValue == "[ignore]" || + sbValue == "[empty]") + { + return string.Empty; + } + + return sbValue; } } diff --git a/deployment/cake/components-tasks.cake b/deployment/cake/components-tasks.cake index 8c81f39..8806b7f 100644 --- a/deployment/cake/components-tasks.cake +++ b/deployment/cake/components-tasks.cake @@ -52,7 +52,8 @@ public class ComponentsProcessor : ProcessorBase { foreach (var component in BuildContext.Components.Items) { - var cacheDirectory = Environment.ExpandEnvironmentVariables(string.Format("%userprofile%/.nuget/packages/{0}/{1}", component, BuildContext.General.Version.NuGet)); + var expandableCacheDirectory = System.IO.Path.Combine("%userprofile%", ".nuget", "packages", component, BuildContext.General.Version.NuGet); + var cacheDirectory = Environment.ExpandEnvironmentVariables(expandableCacheDirectory); CakeContext.Information("Checking for existing local NuGet cached version at '{0}'", cacheDirectory); @@ -175,10 +176,19 @@ public class ComponentsProcessor : ProcessorBase foreach (var component in BuildContext.Components.Items) { + // Note: some projects, such as Catel.Fody, require packaging + // of non-deployable projects + if (BuildContext.General.SkipComponentsThatAreNotDeployable && + !ShouldDeployProject(BuildContext, component)) + { + CakeContext.Information("Component '{0}' should not be deployed", component); + continue; + } + BuildContext.CakeContext.LogSeparator("Packaging component '{0}'", component); - var projectDirectory = string.Format("./src/{0}", component); - var projectFileName = string.Format("{0}/{1}.csproj", projectDirectory, component); + var projectDirectory = GetProjectDirectory(component); + var projectFileName = GetProjectFileName(BuildContext, component); var outputDirectory = GetProjectOutputDirectory(BuildContext, component); CakeContext.Information("Output directory: '{0}'", outputDirectory); @@ -297,7 +307,7 @@ public class ComponentsProcessor : ProcessorBase BuildContext.CakeContext.LogSeparator("Deploying component '{0}'", component); - var packageToPush = string.Format("{0}/{1}.{2}.nupkg", BuildContext.General.OutputRootDirectory, component, BuildContext.General.Version.NuGet); + var packageToPush = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, $"{component}.{BuildContext.General.Version.NuGet}.nupkg"); var nuGetRepositoryUrl = GetComponentNuGetRepositoryUrl(component); var nuGetRepositoryApiKey = GetComponentNuGetRepositoryApiKey(component); diff --git a/deployment/cake/docker-tasks.cake b/deployment/cake/docker-tasks.cake index 9b325a4..6673fba 100644 --- a/deployment/cake/docker-tasks.cake +++ b/deployment/cake/docker-tasks.cake @@ -133,7 +133,7 @@ public class DockerImagesProcessor : ProcessorBase // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which // are properties passed in using the command line) - var outputDirectory = string.Format("{0}/{1}/", BuildContext.General.OutputRootDirectory, dockerImage); + var outputDirectory = GetProjectOutputDirectory(BuildContext, dockerImage); CakeContext.Information("Output directory: '{0}'", outputDirectory); msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); @@ -156,18 +156,24 @@ public class DockerImagesProcessor : ProcessorBase foreach (var dockerImage in BuildContext.DockerImages.Items) { + if (!ShouldDeployProject(BuildContext, dockerImage)) + { + CakeContext.Information("Docker image '{0}' should not be deployed", dockerImage); + continue; + } + BuildContext.CakeContext.LogSeparator("Packaging docker image '{0}'", dockerImage); - var projectFileName = string.Format("./src/{0}/{0}.csproj", dockerImage); - var dockerImageSpecificationDirectory = string.Format("./deployment/docker/{0}/", dockerImage); - var dockerImageSpecificationFileName = string.Format("{0}/{1}", dockerImageSpecificationDirectory, dockerImage); + var projectFileName = GetProjectFileName(BuildContext, dockerImage); + var dockerImageSpecificationDirectory = System.IO.Path.Combine(".", "deployment", "docker", dockerImage); + var dockerImageSpecificationFileName = System.IO.Path.Combine(dockerImageSpecificationDirectory, dockerImage); - var outputRootDirectory = string.Format("{0}/{1}/output", BuildContext.General.OutputRootDirectory, dockerImage); + var outputRootDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, dockerImage, "output"); CakeContext.Information("1) Preparing ./config for package '{0}'", dockerImage); // ./config - var confTargetDirectory = string.Format("{0}/conf", outputRootDirectory); + var confTargetDirectory = System.IO.Path.Combine(outputRootDirectory, "conf"); CakeContext.Information("Conf directory: '{0}'", confTargetDirectory); CakeContext.CreateDirectory(confTargetDirectory); @@ -182,7 +188,7 @@ public class DockerImagesProcessor : ProcessorBase CakeContext.Information("2) Preparing ./output using 'dotnet publish' for package '{0}'", dockerImage); // ./output - var outputDirectory = string.Format("{0}/output", outputRootDirectory); + var outputDirectory = System.IO.Path.Combine(outputRootDirectory, "output"); CakeContext.Information("Output directory: '{0}'", outputDirectory); var msBuildSettings = new DotNetCoreMSBuildSettings(); diff --git a/deployment/cake/generic-tasks.cake b/deployment/cake/generic-tasks.cake index 603faba..772bb76 100644 --- a/deployment/cake/generic-tasks.cake +++ b/deployment/cake/generic-tasks.cake @@ -4,7 +4,7 @@ #addin "nuget:?package=Cake.FileHelpers&version=3.0.0" #addin "nuget:?package=Cake.DependencyCheck&version=1.2.0" -#tool "nuget:?package=DependencyCheck.Runner.Tool&include=./**/dependency-check.sh&include=./**/dependency-check.bat" +#tool "nuget:?package=DependencyCheck.Runner.Tool&version=3.2.1&include=./**/dependency-check.sh&include=./**/dependency-check.bat" #tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.1.3" //------------------------------------------------------------- diff --git a/deployment/cake/generic-variables.cake b/deployment/cake/generic-variables.cake index 330253b..8962fc0 100644 --- a/deployment/cake/generic-variables.cake +++ b/deployment/cake/generic-variables.cake @@ -1,5 +1,7 @@ #l "buildserver.cake" +#tool "nuget:?package=GitVersion.CommandLine&version=5.3.5" + //------------------------------------------------------------- public class GeneralContext : BuildContextWithItemsBase @@ -7,6 +9,7 @@ public class GeneralContext : BuildContextWithItemsBase public GeneralContext(IBuildContext parentBuildContext) : base(parentBuildContext) { + SkipComponentsThatAreNotDeployable = true; } public string Target { get; set; } @@ -21,6 +24,7 @@ public class GeneralContext : BuildContextWithItemsBase public bool MaximizePerformance { get; set; } public bool UseVisualStudioPrerelease { get; set; } public bool VerifyDependencies { get; set; } + public bool SkipComponentsThatAreNotDeployable { get; set; } public VersionContext Version { get; set; } public CopyrightContext Copyright { get; set; } @@ -77,7 +81,7 @@ public class VersionContext : BuildContextBase // Make a *BIG* assumption that the solution name == repository name var repositoryName = generalContext.Solution.Name; - var tempDirectory = $"{System.IO.Path.GetTempPath()}\\{repositoryName}"; + var tempDirectory = System.IO.Path.Combine(System.IO.Path.GetTempPath(), repositoryName); if (CakeContext.DirectoryExists(tempDirectory)) { @@ -200,16 +204,11 @@ public class SolutionContext : BuildContextBase get { var directory = System.IO.Directory.GetParent(FileName).FullName; - if (!directory.EndsWith("/") && !directory.EndsWith("\\")) + var separator = System.IO.Path.DirectorySeparatorChar.ToString(); + + if (!directory.EndsWith(separator)) { - if (directory.Contains("\\")) - { - directory += "\\"; - } - else - { - directory += "/"; - } + directory += separator; } return directory; @@ -387,6 +386,7 @@ private GeneralContext InitializeGeneralContext(BuildContext buildContext, IBuil data.MaximizePerformance = buildContext.BuildServer.GetVariableAsBool("MaximizePerformance", true, showValue: true); data.UseVisualStudioPrerelease = buildContext.BuildServer.GetVariableAsBool("UseVisualStudioPrerelease", false, showValue: true); data.VerifyDependencies = !buildContext.BuildServer.GetVariableAsBool("DependencyCheckDisabled", false, showValue: true); + data.SkipComponentsThatAreNotDeployable = buildContext.BuildServer.GetVariableAsBool("SkipComponentsThatAreNotDeployable", true, showValue: true); // If local, we want full pdb, so do a debug instead if (data.IsLocalBuild) diff --git a/deployment/cake/github-pages-tasks.cake b/deployment/cake/github-pages-tasks.cake index 3c6c65a..282fd4c 100644 --- a/deployment/cake/github-pages-tasks.cake +++ b/deployment/cake/github-pages-tasks.cake @@ -114,7 +114,7 @@ public class GitHubPagesProcessor : ProcessorBase // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which // are properties passed in using the command line) - var outputDirectory = string.Format("{0}/{1}/", BuildContext.General.OutputRootDirectory, gitHubPage); + var outputDirectory = GetProjectOutputDirectory(BuildContext, gitHubPage); CakeContext.Information("Output directory: '{0}'", outputDirectory); msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); @@ -133,11 +133,17 @@ public class GitHubPagesProcessor : ProcessorBase foreach (var gitHubPage in BuildContext.GitHubPages.Items) { - BuildContext.CakeContext.LogSeparator("Packaging GitHub pages '{0}'", gitHubPage); + if (!ShouldDeployProject(BuildContext, gitHubPage)) + { + CakeContext.Information("GitHub page '{0}' should not be deployed", gitHubPage); + continue; + } - var projectFileName = string.Format("./src/{0}/{0}.csproj", gitHubPage); + BuildContext.CakeContext.LogSeparator("Packaging GitHub pages '{0}'", gitHubPage); - var outputDirectory = string.Format("{0}/{1}/", BuildContext.General.OutputRootDirectory, gitHubPage); + var projectFileName = GetProjectFileName(BuildContext, gitHubPage); + var outputDirectory = GetProjectOutputDirectory(BuildContext, gitHubPage); + CakeContext.Information("Output directory: '{0}'", outputDirectory); CakeContext.Information("1) Using 'dotnet publish' to package '{0}'", gitHubPage); @@ -203,7 +209,7 @@ public class GitHubPagesProcessor : ProcessorBase CakeContext.Information("2) Updating the GitHub pages branch with latest source"); // Special directory we need to distribute (e.g. output\Release\Blazorc.PatternFly.Example\Blazorc.PatternFly.Example\dist) - var sourceDirectory = string.Format("{0}/{1}/{1}/dist", BuildContext.General.OutputRootDirectory, gitHubPage); + var sourceDirectory = string.Format("{0}/{1}/wwwroot", BuildContext.General.OutputRootDirectory, gitHubPage); var sourcePattern = string.Format("{0}/**/*", sourceDirectory); CakeContext.Debug("Copying all files from '{0}' => '{1}'", sourcePattern, temporaryDirectory); diff --git a/deployment/cake/installers-innosetup.cake b/deployment/cake/installers-innosetup.cake index 2439d71..220cbc5 100644 --- a/deployment/cake/installers-innosetup.cake +++ b/deployment/cake/installers-innosetup.cake @@ -29,7 +29,7 @@ public class InnoSetupInstaller : IInstaller return; } - var innoSetupTemplateDirectory = string.Format("./deployment/innosetup/{0}", projectName); + var innoSetupTemplateDirectory = System.IO.Path.Combine(".", "deployment", "innosetup", projectName); if (!BuildContext.CakeContext.DirectoryExists(innoSetupTemplateDirectory)) { BuildContext.CakeContext.Information("Skip packaging of app '{0}' using Inno Setup since no Inno Setup template is present"); @@ -38,14 +38,14 @@ public class InnoSetupInstaller : IInstaller BuildContext.CakeContext.LogSeparator("Packaging app '{0}' using Inno Setup", projectName); - var installersOnDeploymentsShare = string.Format("{0}/{1}/installer", BuildContext.Wpf.DeploymentsShare, projectName); + var installersOnDeploymentsShare = System.IO.Path.Combine(BuildContext.Wpf.DeploymentsShare, projectName, "installer"); BuildContext.CakeContext.CreateDirectory(installersOnDeploymentsShare); var setupSuffix = BuildContext.Installer.GetDeploymentChannelSuffix(); - var innoSetupOutputRoot = string.Format("{0}/innosetup/{1}", BuildContext.General.OutputRootDirectory, projectName); - var innoSetupReleasesRoot = string.Format("{0}/releases", innoSetupOutputRoot); - var innoSetupOutputIntermediate = string.Format("{0}/intermediate", innoSetupOutputRoot); + var innoSetupOutputRoot = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "innosetup", projectName); + var innoSetupReleasesRoot = System.IO.Path.Combine(innoSetupOutputRoot, "releases"); + var innoSetupOutputIntermediate = System.IO.Path.Combine(innoSetupOutputRoot, "intermediate"); BuildContext.CakeContext.CreateDirectory(innoSetupReleasesRoot); BuildContext.CakeContext.CreateDirectory(innoSetupOutputIntermediate); @@ -53,7 +53,7 @@ public class InnoSetupInstaller : IInstaller // Set up InnoSetup template BuildContext.CakeContext.CopyDirectory(innoSetupTemplateDirectory, innoSetupOutputIntermediate); - var innoSetupScriptFileName = string.Format("{0}/setup.iss", innoSetupOutputIntermediate); + var innoSetupScriptFileName = System.IO.Path.Combine(innoSetupOutputIntermediate, "setup.iss"); var fileContents = System.IO.File.ReadAllText(innoSetupScriptFileName); fileContents = fileContents.Replace("[CHANNEL_SUFFIX]", setupSuffix); fileContents = fileContents.Replace("[CHANNEL]", BuildContext.Installer.GetDeploymentChannelSuffix(" (", ")")); @@ -93,9 +93,9 @@ public class InnoSetupInstaller : IInstaller // - Setup.exe => [projectName]-[version].exe // - Setup.exe => [projectName]-[channel].exe - var installerSourceFile = $"{innoSetupReleasesRoot}/{projectName}_{BuildContext.General.Version.FullSemVer}.exe"; - BuildContext.CakeContext.CopyFile(installerSourceFile, string.Format("{0}/{1}_{2}.exe", installersOnDeploymentsShare, projectName, BuildContext.General.Version.FullSemVer)); - BuildContext.CakeContext.CopyFile(installerSourceFile, string.Format("{0}/{1}{2}.exe", installersOnDeploymentsShare, projectName, setupSuffix)); + var installerSourceFile = System.IO.Path.Combine(innoSetupReleasesRoot, $"{projectName}_{BuildContext.General.Version.FullSemVer}.exe"); + BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}_{BuildContext.General.Version.FullSemVer}.exe")); + BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}{setupSuffix}.exe")); } } } diff --git a/deployment/cake/installers-msix.cake b/deployment/cake/installers-msix.cake index 186fd4d..dbc5d41 100644 --- a/deployment/cake/installers-msix.cake +++ b/deployment/cake/installers-msix.cake @@ -46,7 +46,7 @@ public class MsixInstaller : IInstaller return; } - var msixTemplateDirectory = string.Format("./deployment/msix/{0}", projectName); + var msixTemplateDirectory = System.IO.Path.Combine(".", "deployment", "msix", projectName); if (!BuildContext.CakeContext.DirectoryExists(msixTemplateDirectory)) { BuildContext.CakeContext.Information("Skip packaging of app '{0}' using MSIX since no MSIX template is present"); @@ -66,14 +66,14 @@ public class MsixInstaller : IInstaller BuildContext.CakeContext.LogSeparator("Packaging app '{0}' using MSIX", projectName); - var installersOnDeploymentsShare = $"{BuildContext.Wpf.DeploymentsShare}/{projectName}/{channel}/msix"; + var installersOnDeploymentsShare = System.IO.Path.Combine(BuildContext.Wpf.DeploymentsShare, projectName, channel, "msix"); BuildContext.CakeContext.CreateDirectory(installersOnDeploymentsShare); var setupSuffix = BuildContext.Installer.GetDeploymentChannelSuffix(); - var msixOutputRoot = string.Format("{0}/msix/{1}", BuildContext.General.OutputRootDirectory, projectName); - var msixReleasesRoot = string.Format("{0}/releases", msixOutputRoot); - var msixOutputIntermediate = string.Format("{0}/intermediate", msixOutputRoot); + var msixOutputRoot = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "msix", projectName); + var msixReleasesRoot = System.IO.Path.Combine(msixOutputRoot, "releases"); + var msixOutputIntermediate = System.IO.Path.Combine(msixOutputRoot, "intermediate"); BuildContext.CakeContext.CreateDirectory(msixReleasesRoot); BuildContext.CakeContext.CreateDirectory(msixOutputIntermediate); @@ -82,7 +82,7 @@ public class MsixInstaller : IInstaller BuildContext.CakeContext.CopyDirectory(msixTemplateDirectory, msixOutputIntermediate); var msixInstallerName = $"{projectName}_{BuildContext.General.Version.FullSemVer}.msix"; - var installerSourceFile = $"{msixReleasesRoot}/{msixInstallerName}"; + var installerSourceFile = System.IO.Path.Combine(msixReleasesRoot, msixInstallerName); var variables = new Dictionary(); variables["[PRODUCT]"] = projectName; @@ -102,12 +102,12 @@ public class MsixInstaller : IInstaller variables["[URL_MSIX]"] = $"{UpdateUrl}/{projectName}/{channel}/msix/{msixInstallerName}".ToLower(); // Installer file - var msixScriptFileName = string.Format("{0}/AppxManifest.xml", msixOutputIntermediate); + var msixScriptFileName = System.IO.Path.Combine(msixOutputIntermediate, "AppxManifest.xml"); ReplaceVariablesInFile(msixScriptFileName, variables); // Update file - var msixUpdateScriptFileName = string.Format("{0}/App.AppInstaller", msixOutputIntermediate); + var msixUpdateScriptFileName = System.IO.Path.Combine(msixOutputIntermediate, "App.AppInstaller"); if (BuildContext.CakeContext.FileExists(msixUpdateScriptFileName)) { ReplaceVariablesInFile(msixUpdateScriptFileName, variables); @@ -169,7 +169,7 @@ public class MsixInstaller : IInstaller BuildContext.CakeContext.Information("Copying update manifest to output directory"); // - App.AppInstaller => [projectName].AppInstaller - BuildContext.CakeContext.CopyFile(msixUpdateScriptFileName, $"{msixReleasesRoot}/{projectName}.AppInstaller"); + BuildContext.CakeContext.CopyFile(msixUpdateScriptFileName, System.IO.Path.Combine(msixReleasesRoot, $"{projectName}.AppInstaller")); } if (BuildContext.Wpf.UpdateDeploymentsShare) @@ -180,13 +180,13 @@ public class MsixInstaller : IInstaller // - [ProjectName]_[version].msix => [projectName]_[version].msix // - [ProjectName]_[version].msix => [projectName]_[channel].msix - BuildContext.CakeContext.CopyFile(installerSourceFile, $"{installersOnDeploymentsShare}/{msixInstallerName}"); - BuildContext.CakeContext.CopyFile(installerSourceFile, $"{installersOnDeploymentsShare}/{projectName}{setupSuffix}.msix"); + BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, msixInstallerName)); + BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}{setupSuffix}.msix")); if (BuildContext.CakeContext.FileExists(msixUpdateScriptFileName)) { // - App.AppInstaller => [projectName].AppInstaller - BuildContext.CakeContext.CopyFile(msixUpdateScriptFileName, $"{installersOnDeploymentsShare}/{projectName}.AppInstaller"); + BuildContext.CakeContext.CopyFile(msixUpdateScriptFileName, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}.AppInstaller")); } } } @@ -263,7 +263,7 @@ public class MsixInstaller : IInstaller var directory = FindLatestWindowsKitsDirectory(); if (directory != null) { - return $"{directory}\\x64\\signtool.exe"; + return System.IO.Path.Combine(directory, "x64", "signtool.exe"); } return null; @@ -274,7 +274,7 @@ public class MsixInstaller : IInstaller var directory = FindLatestWindowsKitsDirectory(); if (directory != null) { - return $"{directory}\\x64\\makeappx.exe"; + return System.IO.Path.Combine(directory, "x64", "makeappx.exe"); } return null; diff --git a/deployment/cake/installers-squirrel.cake b/deployment/cake/installers-squirrel.cake index 841e1af..a5c1e0a 100644 --- a/deployment/cake/installers-squirrel.cake +++ b/deployment/cake/installers-squirrel.cake @@ -33,13 +33,13 @@ public class SquirrelInstaller : IInstaller return; } - var squirrelOutputRoot = string.Format("{0}/squirrel/{1}/{2}", BuildContext.General.OutputRootDirectory, projectName, channel); - var squirrelReleasesRoot = string.Format("{0}/releases", squirrelOutputRoot); - var squirrelOutputIntermediate = string.Format("{0}/intermediate", squirrelOutputRoot); + var squirrelOutputRoot = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "squirrel", projectName, channel); + var squirrelReleasesRoot = System.IO.Path.Combine(squirrelOutputRoot, "releases"); + var squirrelOutputIntermediate = System.IO.Path.Combine(squirrelOutputRoot, "intermediate"); - var nuSpecTemplateFileName = string.Format("./deployment/squirrel/template/{0}.nuspec", projectName); - var nuSpecFileName = string.Format("{0}/{1}.nuspec", squirrelOutputIntermediate, projectName); - var nuGetFileName = string.Format("{0}/{1}.{2}.nupkg", squirrelOutputIntermediate, projectName, BuildContext.General.Version.NuGet); + var nuSpecTemplateFileName = System.IO.Path.Combine(".", "deployment", "squirrel", "template", $"{projectName}.nuspec"); + var nuSpecFileName = System.IO.Path.Combine(squirrelOutputIntermediate, $"{projectName}.nuspec"); + var nuGetFileName = System.IO.Path.Combine(squirrelOutputIntermediate, $"{projectName}.{BuildContext.General.Version.NuGet}.nupkg"); if (!BuildContext.CakeContext.FileExists(nuSpecTemplateFileName)) { @@ -73,8 +73,8 @@ public class SquirrelInstaller : IInstaller System.IO.File.WriteAllText(nuSpecFileName, fileContents); // Copy all files to the lib so Squirrel knows what to do - var appSourceDirectory = string.Format("{0}/{1}", BuildContext.General.OutputRootDirectory, projectName); - var appTargetDirectory = string.Format("{0}/lib", squirrelOutputIntermediate); + var appSourceDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, projectName); + var appTargetDirectory = System.IO.Path.Combine(squirrelOutputIntermediate, "lib"); BuildContext.CakeContext.Information("Copying files from '{0}' => '{1}'", appSourceDirectory, appTargetDirectory); @@ -89,8 +89,8 @@ public class SquirrelInstaller : IInstaller // Rename so we have the right nuget package file names (without the channel) if (!string.IsNullOrWhiteSpace(setupSuffix)) { - var sourcePackageFileName = $"{squirrelOutputIntermediate}/{projectName}{setupSuffix}.{BuildContext.General.Version.NuGet}.nupkg"; - var targetPackageFileName = $"{squirrelOutputIntermediate}/{projectName}.{BuildContext.General.Version.NuGet}.nupkg"; + var sourcePackageFileName = System.IO.Path.Combine(squirrelOutputIntermediate, $"{projectName}{setupSuffix}.{BuildContext.General.Version.NuGet}.nupkg"); + var targetPackageFileName = System.IO.Path.Combine(squirrelOutputIntermediate, $"{projectName}.{BuildContext.General.Version.NuGet}.nupkg"); BuildContext.CakeContext.Information("Moving file from '{0}' => '{1}'", sourcePackageFileName, targetPackageFileName); @@ -98,7 +98,7 @@ public class SquirrelInstaller : IInstaller } // Copy deployments share to the intermediate root so we can locally create the Squirrel releases - var releasesSourceDirectory = string.Format("{0}/{1}/{2}", BuildContext.Wpf.DeploymentsShare, projectName, channel); + var releasesSourceDirectory = System.IO.Path.Combine(BuildContext.Wpf.DeploymentsShare, projectName, channel); var releasesTargetDirectory = squirrelReleasesRoot; BuildContext.CakeContext.Information("Copying releases from '{0}' => '{1}'", releasesSourceDirectory, releasesTargetDirectory); @@ -109,11 +109,11 @@ public class SquirrelInstaller : IInstaller var squirrelSettings = new SquirrelSettings(); squirrelSettings.NoMsi = false; squirrelSettings.ReleaseDirectory = squirrelReleasesRoot; - squirrelSettings.LoadingGif = "./deployment/squirrel/loading.gif"; + squirrelSettings.LoadingGif = System.IO.Path.Combine(".", "deployment", "squirrel", "loading.gif"); // Note: this is not really generic, but this is where we store our icons file, we can // always change this in the future - var iconFileName = $"./design/logo/logo{setupSuffix}.ico"; + var iconFileName = System.IO.Path.Combine(".", "design", "logo", $"logo{setupSuffix}.ico"); squirrelSettings.Icon = iconFileName; squirrelSettings.SetupIcon = iconFileName; @@ -140,10 +140,10 @@ public class SquirrelInstaller : IInstaller var squirrelFiles = BuildContext.CakeContext.GetFiles($"{squirrelReleasesRoot}/{projectName}{setupSuffix}-{BuildContext.General.Version.NuGet}*.nupkg"); BuildContext.CakeContext.CopyFiles(squirrelFiles, releasesSourceDirectory); - BuildContext.CakeContext.CopyFile(string.Format("{0}/Setup.exe", squirrelReleasesRoot), string.Format("{0}/Setup.exe", releasesSourceDirectory)); - BuildContext.CakeContext.CopyFile(string.Format("{0}/Setup.exe", squirrelReleasesRoot), string.Format("{0}/{1}.exe", releasesSourceDirectory, projectName)); - BuildContext.CakeContext.CopyFile(string.Format("{0}/Setup.msi", squirrelReleasesRoot), string.Format("{0}/Setup.msi", releasesSourceDirectory)); - BuildContext.CakeContext.CopyFile(string.Format("{0}/RELEASES", squirrelReleasesRoot), string.Format("{0}/RELEASES", releasesSourceDirectory)); + BuildContext.CakeContext.CopyFile(System.IO.Path.Combine(squirrelReleasesRoot, "Setup.exe"), System.IO.Path.Combine(releasesSourceDirectory, "Setup.exe")); + BuildContext.CakeContext.CopyFile(System.IO.Path.Combine(squirrelReleasesRoot, "Setup.exe"), System.IO.Path.Combine(releasesSourceDirectory, $"{projectName}.exe")); + BuildContext.CakeContext.CopyFile(System.IO.Path.Combine(squirrelReleasesRoot, "Setup.msi"), System.IO.Path.Combine(releasesSourceDirectory, "Setup.msi")); + BuildContext.CakeContext.CopyFile(System.IO.Path.Combine(squirrelReleasesRoot, "RELEASES"), System.IO.Path.Combine(releasesSourceDirectory, "RELEASES")); } } } \ No newline at end of file diff --git a/deployment/cake/lib-generic.cake b/deployment/cake/lib-generic.cake index 479fa4f..9922c85 100644 --- a/deployment/cake/lib-generic.cake +++ b/deployment/cake/lib-generic.cake @@ -324,6 +324,9 @@ private static void ConfigureMsBuild(BuildContext buildContext, MSBuildSettings msBuildSettings.ToolPath = toolPath; } + // Continuous integration build + msBuildSettings.WithProperty("ContinuousIntegrationBuild", "true"); + // No NuGet restore (should already be done) msBuildSettings.WithProperty("ResolveNuGetPackages", "false"); msBuildSettings.Restore = false; @@ -369,6 +372,9 @@ private static void ConfigureMsBuildForDotNetCore(BuildContext buildContext, Dot msBuildSettings.ToolPath = toolPath; } + // Continuous integration build + msBuildSettings.WithProperty("ContinuousIntegrationBuild", "true"); + // No NuGet restore (should already be done) msBuildSettings.WithProperty("ResolveNuGetPackages", "false"); //msBuildSettings.Restore = false; @@ -426,42 +432,31 @@ private static string GetVisualStudioDirectory(BuildContext buildContext, bool? //buildContext.General.SonarQube.IsDisabled = true; return pathFor2019Preview; } - - buildContext.CakeContext.Debug("Checking for installation of Visual Studio 2017 preview"); - - var pathFor2017Preview = @"C:\Program Files (x86)\Microsoft Visual Studio\Preview\Professional\"; - if (System.IO.Directory.Exists(pathFor2017Preview)) - { - buildContext.CakeContext.Information("Using Visual Studio 2017 preview"); - return pathFor2017Preview; - } } buildContext.CakeContext.Debug("Checking for installation of Visual Studio 2019"); - var pathFor2019 = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\"; - if (System.IO.Directory.Exists(pathFor2019)) + var pathFor2019Enterprise = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\"; + if (System.IO.Directory.Exists(pathFor2019Enterprise)) { - buildContext.CakeContext.Information("Using Visual Studio 2019"); - return pathFor2019; + buildContext.CakeContext.Information("Using Visual Studio 2019 Enterprise"); + return pathFor2019Enterprise; + } + + var pathFor2019Professional = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\"; + if (System.IO.Directory.Exists(pathFor2019Professional)) + { + buildContext.CakeContext.Information("Using Visual Studio 2019 Professional"); + return pathFor2019Professional; } - var pathFor2019Community = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\"; + var pathFor2019Community = @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\"; if (System.IO.Directory.Exists(pathFor2019Community)) { buildContext.CakeContext.Information("Using Visual Studio 2019 CE"); return pathFor2019Community; } - buildContext.CakeContext.Debug("Checking for installation of Visual Studio 2017"); - - var pathFor2017 = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\"; - if (System.IO.Directory.Exists(pathFor2017)) - { - buildContext.CakeContext.Information("Using Visual Studio 2017"); - return pathFor2017; - } - // Failed return null; } @@ -480,7 +475,7 @@ private static string GetVisualStudioPath(BuildContext buildContext, bool? allow foreach (var potentialPath in potentialPaths) { - var pathToCheck = string.Format(@"{0}\{1}", directory, potentialPath); + var pathToCheck = System.IO.Path.Combine(directory, potentialPath); if (System.IO.File.Exists(pathToCheck)) { return pathToCheck; @@ -501,7 +496,7 @@ private static bool IsCppProject(string projectName) private static string GetProjectDirectory(string projectName) { - var projectDirectory = string.Format("./src/{0}/", projectName); + var projectDirectory = System.IO.Path.Combine(".", "src", projectName); return projectDirectory; } @@ -509,7 +504,7 @@ private static string GetProjectDirectory(string projectName) private static string GetProjectOutputDirectory(BuildContext buildContext, string projectName) { - var projectDirectory = string.Format("{0}/{1}", buildContext.General.OutputRootDirectory, projectName); + var projectDirectory = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, projectName); return projectDirectory; } @@ -525,8 +520,8 @@ private static string GetProjectFileName(BuildContext buildContext, string proje foreach (var allowedExtension in allowedExtensions) { - var fileName = string.Format("{0}{1}.{2}", GetProjectDirectory(projectName), projectName, allowedExtension); - + var fileName = System.IO.Path.Combine(GetProjectDirectory(projectName), $"{projectName}.{allowedExtension}"); + //buildContext.CakeContext.Information(fileName); if (buildContext.CakeContext.FileExists(fileName)) @@ -536,7 +531,7 @@ private static string GetProjectFileName(BuildContext buildContext, string proje } // Old behavior - var fallbackFileName = string.Format("{0}{1}.{2}", GetProjectDirectory(projectName), projectName, allowedExtensions[0]); + var fallbackFileName = System.IO.Path.Combine(GetProjectDirectory(projectName), $"{projectName}.{allowedExtensions[0]}"); return fallbackFileName; } @@ -544,7 +539,7 @@ private static string GetProjectFileName(BuildContext buildContext, string proje private static string GetProjectSlug(string projectName) { - var slug = projectName.Replace(".", "").Replace(" ", ""); + var slug = projectName.Replace(".", string.Empty).Replace(" ", string.Empty); return slug; } @@ -730,6 +725,23 @@ private static bool ShouldProcessProject(BuildContext buildContext, string proje return process; } + if (buildContext.General.IsCiBuild) + { + // In CI builds, we always want to include all projects + return true; + } + + // Experimental mode where we ignore projects that are not on the deploy list when not in CI mode, but + // it can only work if they are not part of unit tests (but that should never happen) + if (buildContext.Tests.Items.Count == 0) + { + if (!ShouldDeployProject(buildContext, projectName)) + { + buildContext.CakeContext.Warning("Project '{0}' should not be processed because this is not a CI build, does not contain tests and the project should not be deployed, removing from projects to process", projectName); + return false; + } + } + return true; } diff --git a/deployment/cake/lib-sourcelink.cake b/deployment/cake/lib-sourcelink.cake index 745b14b..7bcae42 100644 --- a/deployment/cake/lib-sourcelink.cake +++ b/deployment/cake/lib-sourcelink.cake @@ -51,9 +51,10 @@ public static void InjectSourceLinkInProjectFile(BuildContext buildContext, stri // Required to end with a \ var sourceRootValue = buildContext.General.RootDirectory; - if (!sourceRootValue.EndsWith("\\")) + var directorySeparator = System.IO.Path.DirectorySeparatorChar.ToString(); + if (!sourceRootValue.EndsWith(directorySeparator)) { - sourceRootValue += "\\"; + sourceRootValue += directorySeparator; }; sourceRoot.Add(new XAttribute("Include", sourceRootValue)); diff --git a/deployment/cake/tasks.cake b/deployment/cake/tasks.cake index fc14c78..6676a35 100644 --- a/deployment/cake/tasks.cake +++ b/deployment/cake/tasks.cake @@ -22,7 +22,6 @@ #addin "nuget:?package=Cake.Sonar&version=1.1.25" #tool "nuget:?package=MSBuild.SonarQube.Runner.Tool&version=4.8.0" -#tool "nuget:?package=GitVersion.CommandLine&version=5.1.2-beta1.17&prerelease" //------------------------------------------------------------- // BACKWARDS COMPATIBILITY CODE - START @@ -441,8 +440,9 @@ Task("PackageLocal") { Information("Copying build artifact for '{0}'", component); - var sourceFile = string.Format("{0}/{1}.{2}.nupkg", buildContext.General.OutputRootDirectory, - component, buildContext.General.Version.NuGet); + var sourceFile = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, + $"{component}.{buildContext.General.Version.NuGet}.nupkg"); + CopyFiles(new [] { sourceFile }, localPackagesDirectory); } catch (Exception) diff --git a/deployment/cake/tests-nunit.cake b/deployment/cake/tests-nunit.cake index 024abb6..6d1ce1c 100644 --- a/deployment/cake/tests-nunit.cake +++ b/deployment/cake/tests-nunit.cake @@ -1,11 +1,11 @@ -#tool "nuget:?package=NUnit.ConsoleRunner&version=3.9.0" +#tool "nuget:?package=NUnit.ConsoleRunner&version=3.11.1" //------------------------------------------------------------- private static void RunTestsUsingNUnit(BuildContext buildContext, string projectName, string testTargetFramework, string testResultsDirectory) { - var testFile = string.Format("{0}/{1}/{2}.dll", GetProjectOutputDirectory(buildContext, projectName), - testTargetFramework, projectName); + var testFile = System.IO.Path.Combine(GetProjectOutputDirectory(buildContext, projectName), + testTargetFramework, $"{projectName}.dll"); var resultsFile = string.Format("{0}testresults.xml", testResultsDirectory); // Note: although the docs say you can use without array initialization, you can't diff --git a/deployment/cake/tests.cake b/deployment/cake/tests.cake index 5176ce9..da78cb1 100644 --- a/deployment/cake/tests.cake +++ b/deployment/cake/tests.cake @@ -40,7 +40,7 @@ private static void BuildTestProjects(BuildContext buildContext) // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which // are properties passed in using the command line) - var outputDirectory = string.Format("{0}/{1}/", buildContext.General.OutputRootDirectory, testProject); + var outputDirectory = GetProjectOutputDirectory(buildContext, testProject); buildContext.CakeContext.Information("Output directory: '{0}'", outputDirectory); msBuildSettings.WithProperty("OverridableOutputRootPath", buildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); @@ -54,7 +54,8 @@ private static void BuildTestProjects(BuildContext buildContext) private static void RunUnitTests(BuildContext buildContext, string projectName) { - var testResultsDirectory = string.Format("{0}/testresults/{1}/", buildContext.General.OutputRootDirectory, projectName); + var testResultsDirectory = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, + "testresults", projectName); buildContext.CakeContext.CreateDirectory(testResultsDirectory); @@ -64,7 +65,7 @@ private static void RunUnitTests(BuildContext buildContext, string projectName) try { - if (IsDotNetCoreProject(buildContext, projectName)) + if (testTargetFramework.Contains("netcore") && IsDotNetCoreProject(buildContext, projectName)) { buildContext.CakeContext.Information("Project '{0}' is a .NET core project, using 'dotnet test' to run the unit tests", projectName); @@ -75,7 +76,7 @@ private static void RunUnitTests(BuildContext buildContext, string projectName) Configuration = buildContext.General.Solution.ConfigurationName, NoRestore = true, NoBuild = true, - OutputDirectory = string.Format("{0}/{1}", GetProjectOutputDirectory(buildContext, projectName), testTargetFramework), + OutputDirectory = System.IO.Path.Combine(GetProjectOutputDirectory(buildContext, projectName), testTargetFramework), ResultsDirectory = testResultsDirectory }); diff --git a/deployment/cake/tools-tasks.cake b/deployment/cake/tools-tasks.cake index dbc4f2b..c2b7014 100644 --- a/deployment/cake/tools-tasks.cake +++ b/deployment/cake/tools-tasks.cake @@ -22,13 +22,13 @@ public class ToolsProcessor : ProcessorBase var outputDirectory = GetProjectOutputDirectory(BuildContext, projectName); // Check if it already exists - var fileName = string.Format("{0}/LICENSE.txt", outputDirectory); + var fileName = System.IO.Path.Combine(outputDirectory, "LICENSE.txt"); if (!CakeContext.FileExists(fileName)) { CakeContext.Information("Creating Chocolatey license file for '{0}'", projectName); // Option 1: Copy from root - var sourceFile = "./LICENSE"; + var sourceFile = System.IO.Path.Combine(".", "LICENSE"); if (CakeContext.FileExists(sourceFile)) { CakeContext.Information("Using license file from repository"); @@ -50,7 +50,7 @@ public class ToolsProcessor : ProcessorBase var outputDirectory = GetProjectOutputDirectory(BuildContext, projectName); // Check if it already exists - var fileName = string.Format("{0}/VERIFICATION.txt", outputDirectory); + var fileName = System.IO.Path.Combine(outputDirectory, "VERIFICATION.txt"); if (!CakeContext.FileExists(fileName)) { CakeContext.Information("Creating Chocolatey verification file for '{0}'", projectName); @@ -102,8 +102,8 @@ public class ToolsProcessor : ProcessorBase { foreach (var tool in BuildContext.Tools.Items) { - var cacheDirectory = Environment.ExpandEnvironmentVariables(string.Format("%userprofile%/.nuget/packages/{0}/{1}", - tool, BuildContext.General.Version.NuGet)); + var expandableCacheDirectory = System.IO.Path.Combine("%userprofile%", ".nuget", "packages", tool, BuildContext.General.Version.NuGet); + var cacheDirectory = Environment.ExpandEnvironmentVariables(expandableCacheDirectory); CakeContext.Information("Checking for existing local NuGet cached version at '{0}'", cacheDirectory); @@ -223,10 +223,16 @@ public class ToolsProcessor : ProcessorBase foreach (var tool in BuildContext.Tools.Items) { + if (!ShouldDeployProject(BuildContext, tool)) + { + CakeContext.Information("Tool '{0}' should not be deployed", tool); + continue; + } + BuildContext.CakeContext.LogSeparator("Packaging tool '{0}'", tool); - var projectDirectory = string.Format("./src/{0}", tool); - var projectFileName = string.Format("{0}/{1}.csproj", projectDirectory, tool); + var projectDirectory = System.IO.Path.Combine(".", "src", tool); + var projectFileName = System.IO.Path.Combine(projectDirectory, $"{tool}.csproj"); var outputDirectory = GetProjectOutputDirectory(BuildContext, tool); CakeContext.Information("Output directory: '{0}'", outputDirectory); @@ -358,7 +364,7 @@ public class ToolsProcessor : ProcessorBase BuildContext.CakeContext.LogSeparator("Deploying tool '{0}'", tool); - var packageToPush = string.Format("{0}/{1}.{2}.nupkg", BuildContext.General.OutputRootDirectory, tool, version); + var packageToPush = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, $"{tool}.{version}.nupkg"); var nuGetRepositoryUrls = GetToolsNuGetRepositoryUrls(tool); var nuGetRepositoryApiKeys = GetToolsNuGetRepositoryApiKeys(tool); diff --git a/deployment/cake/vsextensions-tasks.cake b/deployment/cake/vsextensions-tasks.cake index 73321e1..5152530 100644 --- a/deployment/cake/vsextensions-tasks.cake +++ b/deployment/cake/vsextensions-tasks.cake @@ -55,7 +55,7 @@ public class VsExtensionsProcessor : ProcessorBase var projectDirectory = GetProjectDirectory(vsExtension); // Step 1: update vsix manifest - var vsixManifestFileName = string.Format("{0}\\source.extension.vsixmanifest", projectDirectory); + var vsixManifestFileName = System.IO.Path.Combine(projectDirectory, "source.extension.vsixmanifest"); CakeContext.TransformConfig(vsixManifestFileName, new TransformationCollection { @@ -123,8 +123,8 @@ public class VsExtensionsProcessor : ProcessorBase return; } - var vsixPublisherExeDirectory = string.Format(@"{0}\VSSDK\VisualStudioIntegration\Tools\Bin", GetVisualStudioDirectory(BuildContext)); - var vsixPublisherExeFileName = string.Format(@"{0}\VsixPublisher.exe", vsixPublisherExeDirectory); + var vsixPublisherExeDirectory = System.IO.Path.Combine(GetVisualStudioDirectory(BuildContext), "VSSDK", "VisualStudioIntegration", "Tools", "Bin"); + var vsixPublisherExeFileName = System.IO.Path.Combine(vsixPublisherExeDirectory, "VsixPublisher.exe"); foreach (var vsExtension in BuildContext.VsExtensions.Items) { @@ -138,14 +138,14 @@ public class VsExtensionsProcessor : ProcessorBase // Step 1: copy the output stuff var vsExtensionOutputDirectory = GetProjectOutputDirectory(BuildContext, vsExtension); - var payloadFileName = string.Format(@"{0}\{1}.vsix", vsExtensionOutputDirectory, vsExtension); + var payloadFileName = System.IO.Path.Combine(vsExtensionOutputDirectory, $"{vsExtension}.vsix"); - var overviewSourceFileName = string.Format(@"src\{0}\overview.md", vsExtension); - var overviewTargetFileName = string.Format(@"{0}\overview.md", vsExtensionOutputDirectory); + var overviewSourceFileName = System.IO.Path.Combine("src", vsExtension, "overview.md"); + var overviewTargetFileName = System.IO.Path.Combine(vsExtensionOutputDirectory, "overview.md"); CakeContext.CopyFile(overviewSourceFileName, overviewTargetFileName); - var vsGalleryManifestSourceFileName = string.Format(@"src\{0}\source.extension.vsgallerymanifest", vsExtension); - var vsGalleryManifestTargetFileName = string.Format(@"{0}\source.extension.vsgallerymanifest", vsExtensionOutputDirectory); + var vsGalleryManifestSourceFileName = System.IO.Path.Combine("src", vsExtension, "source.extension.vsgallerymanifest"); + var vsGalleryManifestTargetFileName = System.IO.Path.Combine(vsExtensionOutputDirectory, "source.extension.vsgallerymanifest"); CakeContext.CopyFile(vsGalleryManifestSourceFileName, vsGalleryManifestTargetFileName); // Step 2: update vs gallery manifest diff --git a/design/Package/Icon.png b/design/Package/Icon.png new file mode 100644 index 0000000..23364be Binary files /dev/null and b/design/Package/Icon.png differ diff --git a/lib/repositories.config b/lib/repositories.config deleted file mode 100644 index 3812cff..0000000 --- a/lib/repositories.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Directory.Build.analyzers.props b/src/Directory.Build.analyzers.props index 9538796..3d7eedc 100644 --- a/src/Directory.Build.analyzers.props +++ b/src/Directory.Build.analyzers.props @@ -4,7 +4,34 @@ --> - - + + build; native; contentfiles; analyzers + + + build; native; contentfiles; analyzers + + + + build; native; contentfiles; analyzers + + + + + + $(NoWarn);CA1030;CA1031;CA1054;CA1062;CA1724;CA1810;CA2007;CA2237 + $(NoError);CA1030;CA1031;CA1054;CA1062;CA1724;CA810;CA2007;CA2237 + \ No newline at end of file diff --git a/src/Directory.Build.shared.explicit.props b/src/Directory.Build.shared.explicit.props index f21390c..b28068a 100644 --- a/src/Directory.Build.shared.explicit.props +++ b/src/Directory.Build.shared.explicit.props @@ -101,6 +101,7 @@ + diff --git a/src/Directory.Build.shared.tests.props b/src/Directory.Build.shared.tests.props new file mode 100644 index 0000000..d577cf1 --- /dev/null +++ b/src/Directory.Build.shared.tests.props @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/MethodTimeLogger.cs b/src/MethodTimeLogger.cs index 50f6caa..1aab872 100644 --- a/src/MethodTimeLogger.cs +++ b/src/MethodTimeLogger.cs @@ -1,6 +1,7 @@ using System.Reflection; using Catel.Logging; using System; +using System.Globalization; /// /// Note: do not rename this class or put it inside a namespace. @@ -26,7 +27,7 @@ public static void Log(Type type, string methodName, long milliseconds, string m return; } - var finalMessage = $"[METHODTIMER] {type.Name}.{methodName} took '{milliseconds.ToString()}' ms"; + var finalMessage = $"[METHODTIMER] {type.Name}.{methodName} took '{milliseconds.ToString(CultureInfo.InvariantCulture)}' ms"; if (!string.IsNullOrWhiteSpace(message)) { diff --git a/src/Orc.CommandLine.Tests/FodyWeavers.xml b/src/Orc.CommandLine.Tests/FodyWeavers.xml index 40947fb..dc86f27 100644 --- a/src/Orc.CommandLine.Tests/FodyWeavers.xml +++ b/src/Orc.CommandLine.Tests/FodyWeavers.xml @@ -1,2 +1,4 @@  - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/Orc.CommandLine.Tests/GlobalInitialization.approvaltests.cs b/src/Orc.CommandLine.Tests/GlobalInitialization.approvaltests.cs index 8062f3b..0a4c97b 100644 --- a/src/Orc.CommandLine.Tests/GlobalInitialization.approvaltests.cs +++ b/src/Orc.CommandLine.Tests/GlobalInitialization.approvaltests.cs @@ -8,23 +8,7 @@ using ApprovalTests.Reporters; #if DEBUG -[assembly: UseReporter(typeof(BeyondCompare4Reporter), typeof(DiffReporter), typeof(AllFailingTestsClipboardReporter))] +[assembly: UseReporter(typeof(BeyondCompareReporter))] #else [assembly: UseReporter(typeof(DiffReporter))] #endif - -public static class TargetFrameworkResolver -{ - public const string Current = - -#if NET45 - "NET45" -#elif NET46 - "NET46" -#elif NET47 - "NET47" -#else - "Unknown" -#endif - ; -} \ No newline at end of file diff --git a/src/Orc.CommandLine.Tests/Orc.CommandLine.Tests.csproj b/src/Orc.CommandLine.Tests/Orc.CommandLine.Tests.csproj index 3507262..56f198f 100644 --- a/src/Orc.CommandLine.Tests/Orc.CommandLine.Tests.csproj +++ b/src/Orc.CommandLine.Tests/Orc.CommandLine.Tests.csproj @@ -1,6 +1,6 @@  - net46 + netcoreapp3.1 Orc.CommandLine.Tests Orc.CommandLine.Tests en-US @@ -12,25 +12,24 @@ - - - - - + + + + runtime; build; native; contentfiles; analyzers - + + - - - - - + + + + - + @@ -41,20 +40,6 @@ - - - True - True - Resources.resx - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - \ No newline at end of file + + diff --git a/src/Orc.CommandLine.Tests/Orc.CommandLine.approved.cs b/src/Orc.CommandLine.Tests/Orc.CommandLine.approved.cs index 4d79ebc..d556151 100644 --- a/src/Orc.CommandLine.Tests/Orc.CommandLine.approved.cs +++ b/src/Orc.CommandLine.Tests/Orc.CommandLine.approved.cs @@ -1,7 +1,7 @@ -[assembly: System.Resources.NeutralResourcesLanguageAttribute("en-US")] -[assembly: System.Runtime.InteropServices.ComVisibleAttribute(false)] -[assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6", FrameworkDisplayName=".NET Framework 4.6")] -public class static ModuleInitializer +[assembly: System.Resources.NeutralResourcesLanguage("en-US")] +[assembly: System.Runtime.InteropServices.ComVisible(false)] +[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v3.1", FrameworkDisplayName="")] +public static class ModuleInitializer { public static void Initialize() { } } @@ -17,9 +17,9 @@ public class CommandLineParser : Orc.CommandLine.ICommandLineParser public CommandLineParser(Orc.CommandLine.IOptionDefinitionService optionDefinitionService, Catel.Services.ILanguageService languageService, Orc.CommandLine.ICommandLineService commandLineService) { } protected virtual System.Text.RegularExpressions.Regex CreateRegex(Orc.CommandLine.IContext targetContext) { } public Catel.Data.IValidationContext Parse(Orc.CommandLine.IContext targetContext) { } - public Catel.Data.IValidationContext Parse(string commandLine, Orc.CommandLine.IContext targetContext) { } public Catel.Data.IValidationContext Parse(System.Collections.Generic.IEnumerable commandLineArguments, Orc.CommandLine.IContext targetContext) { } public Catel.Data.IValidationContext Parse(System.Collections.Generic.List commandLineArguments, Orc.CommandLine.IContext targetContext) { } + public Catel.Data.IValidationContext Parse(string commandLine, Orc.CommandLine.IContext targetContext) { } protected virtual void ValidateMandatorySwitches(Catel.Data.IValidationContext validationContext, System.Collections.Generic.IEnumerable optionDefinitions, System.Collections.Generic.HashSet handledOptions) { } } public class CommandLineService : Orc.CommandLine.ICommandLineService @@ -45,11 +45,11 @@ public System.Collections.Generic.IEnumerable GetHelp(Orc.CommandLine.IC public interface ICommandLineParser { Catel.Data.IValidationContext Parse(Orc.CommandLine.IContext targetContext); - Catel.Data.IValidationContext Parse(System.Collections.Generic.List commandLineArguments, Orc.CommandLine.IContext targetContext); Catel.Data.IValidationContext Parse(System.Collections.Generic.IEnumerable commandLineArguments, Orc.CommandLine.IContext targetContext); + Catel.Data.IValidationContext Parse(System.Collections.Generic.List commandLineArguments, Orc.CommandLine.IContext targetContext); Catel.Data.IValidationContext Parse(string commandLine, Orc.CommandLine.IContext targetContext); } - public class static ICommandLineParserExtensions + public static class ICommandLineParserExtensions { public static System.Collections.Generic.IEnumerable GetAppHeader(this Orc.CommandLine.ICommandLineParser commandLineParser) { } public static System.Collections.Generic.IEnumerable GetHelp(this Orc.CommandLine.ICommandLineParser commandLineParser, Orc.CommandLine.IContext targetContext) { } @@ -75,12 +75,9 @@ public interface IOptionDefinitionService { System.Collections.Generic.IEnumerable GetOptionDefinitions(Orc.CommandLine.IContext targetContext); } - [System.AttributeUsageAttribute(System.AttributeTargets.Property | System.AttributeTargets.All)] + [System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.All)] public class OptionAttribute : System.Attribute { - [System.ObsoleteAttribute("Use string overload instead so multiple characters can be used for the short name" + - ". Will be removed in version 4.0.0.", true)] - public OptionAttribute(char shortName, string longName) { } public OptionAttribute(string shortName, string longName) { } public bool AcceptsValue { get; set; } public string DisplayName { get; set; } @@ -105,7 +102,7 @@ public OptionDefinition() { } public bool TrimWhiteSpace { get; set; } public override string ToString() { } } - public class static OptionDefinitionExtensions + public static class OptionDefinitionExtensions { public static string GetSwitchDisplay(this Orc.CommandLine.OptionDefinition optionDefinition) { } public static bool HasSwitch(this Orc.CommandLine.OptionDefinition optionDefinition) { } @@ -116,11 +113,8 @@ public class OptionDefinitionService : Orc.CommandLine.IOptionDefinitionService public OptionDefinitionService() { } public System.Collections.Generic.IEnumerable GetOptionDefinitions(Orc.CommandLine.IContext targetContext) { } } - public class static StringExtensions + public static class StringExtensions { - [System.ObsoleteAttribute("Use `Environment.GetCommandLineArgs()` instead. Will be removed in version 4.0.0." + - "", true)] - public static string GetCommandLine(this string commandLine, bool removeFirstArgument) { } public static bool IsHelp(this string singleArgument, char[] quoteSplitCharacters) { } public static bool IsSwitch(this string value, char[] quoteSplitCharacters) { } public static bool IsSwitch(this string switchName, string value, char[] quoteSplitCharacters) { } diff --git a/src/Orc.CommandLine.Tests/PublicApiFacts.cs b/src/Orc.CommandLine.Tests/PublicApiFacts.cs index e2f76eb..5d0329d 100644 --- a/src/Orc.CommandLine.Tests/PublicApiFacts.cs +++ b/src/Orc.CommandLine.Tests/PublicApiFacts.cs @@ -7,9 +7,13 @@ namespace Orc.CommandLine.Tests { + using System.IO; + using System.Reflection; using System.Runtime.CompilerServices; - using ApiApprover; + using ApprovalTests; + using ApprovalTests.Namers; using NUnit.Framework; + using PublicApiGenerator; [TestFixture] public class PublicApiFacts @@ -21,5 +25,31 @@ public void Orc_CommandLine_HasNoBreakingChanges() PublicApiApprover.ApprovePublicApi(assembly); } + + internal static class PublicApiApprover + { + public static void ApprovePublicApi(Assembly assembly) + { + var publicApi = ApiGenerator.GeneratePublicApi(assembly, new ApiGeneratorOptions()); + var writer = new ApprovalTextWriter(publicApi, "cs"); + var approvalNamer = new AssemblyPathNamer(assembly.Location); + Approvals.Verify(writer, approvalNamer, Approvals.GetReporter()); + } + } + + internal class AssemblyPathNamer : UnitTestFrameworkNamer + { + private readonly string _name; + + public AssemblyPathNamer(string assemblyPath) + { + _name = Path.GetFileNameWithoutExtension(assemblyPath); + } + + public override string Name + { + get { return _name; } + } + } } -} \ No newline at end of file +} diff --git a/src/Orc.CommandLine/Attributes/OptionAttribute.cs b/src/Orc.CommandLine/Attributes/OptionAttribute.cs index 7a36597..be8dd7f 100644 --- a/src/Orc.CommandLine/Attributes/OptionAttribute.cs +++ b/src/Orc.CommandLine/Attributes/OptionAttribute.cs @@ -12,12 +12,6 @@ namespace Orc.CommandLine [AttributeUsage(AttributeTargets.Property)] public class OptionAttribute : Attribute { - [ObsoleteEx(Message = "Use string overload instead so multiple characters can be used for the short name", TreatAsErrorFromVersion = "3.0", RemoveInVersion = "4.0")] - public OptionAttribute(char shortName, string longName) - : this(shortName.ToString(), longName) - { - } - public OptionAttribute(string shortName, string longName) { ShortName = shortName; @@ -44,4 +38,4 @@ public OptionAttribute(string shortName, string longName) public bool IsMandatory { get; set; } } -} \ No newline at end of file +} diff --git a/src/Orc.CommandLine/Extensions/StringExtensions.cs b/src/Orc.CommandLine/Extensions/StringExtensions.cs index 16de94a..7b1f515 100644 --- a/src/Orc.CommandLine/Extensions/StringExtensions.cs +++ b/src/Orc.CommandLine/Extensions/StringExtensions.cs @@ -15,22 +15,6 @@ public static class StringExtensions { internal static readonly string[] AcceptedSwitchPrefixes = new[] { "-", "/" }; - [ObsoleteEx(RemoveInVersion ="4.0.0", ReplacementTypeOrMember = "Environment.GetCommandLineArgs()", TreatAsErrorFromVersion = "3.3.0")] - public static string GetCommandLine(this string commandLine, bool removeFirstArgument) - { - Argument.IsNotNull(() => commandLine); - - var splittedCommandLine = commandLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); - - if (removeFirstArgument && splittedCommandLine.Count > 0) - { - splittedCommandLine = splittedCommandLine.Skip(1).ToList(); - } - - var finalCommandLine = string.Join(" ", splittedCommandLine.Select(x => x)); - return finalCommandLine; - } - public static bool IsSwitch(this string value, char[] quoteSplitCharacters) { if (string.IsNullOrWhiteSpace(value)) diff --git a/src/Orc.CommandLine/Orc.CommandLine.csproj b/src/Orc.CommandLine/Orc.CommandLine.csproj index a13e2cf..88efe15 100644 --- a/src/Orc.CommandLine/Orc.CommandLine.csproj +++ b/src/Orc.CommandLine/Orc.CommandLine.csproj @@ -1,6 +1,6 @@  - net46;net47;netcoreapp3.0;netstandard2.0 + net46;net47;netcoreapp3.1;netstandard2.0 Orc.CommandLine Orc.CommandLine en-US @@ -16,36 +16,19 @@ - - - - + + + runtime; build; native; contentfiles; analyzers - - + - - True - True - Resources.resx - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - + - \ No newline at end of file + diff --git a/src/Orc.CommandLine/Services/HelpWriterService.cs b/src/Orc.CommandLine/Services/HelpWriterService.cs index 4d025f6..3f76e7c 100644 --- a/src/Orc.CommandLine/Services/HelpWriterService.cs +++ b/src/Orc.CommandLine/Services/HelpWriterService.cs @@ -7,6 +7,7 @@ namespace Orc.CommandLine { + using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -39,9 +40,13 @@ public IEnumerable GetAppHeader() public IEnumerable GetHelp(IContext targetContext) { - var lines = new List(); - var optionDefinitions = _optionDefinitionService.GetOptionDefinitions(targetContext).ToList(); + if (optionDefinitions.Count == 0) + { + return Array.Empty(); + } + + var lines = new List(); var prefixLength = optionDefinitions.Select(x => x.ToString().Length).Max(); diff --git a/src/SolutionAssemblyInfo.cs b/src/SolutionAssemblyInfo.cs index e6402f0..4b936af 100644 --- a/src/SolutionAssemblyInfo.cs +++ b/src/SolutionAssemblyInfo.cs @@ -6,8 +6,8 @@ using System.Reflection; [assembly: AssemblyCompany("WildGums")] -[assembly: AssemblyVersion("3.3.0")] -[assembly: AssemblyFileVersion("3.3.0")] -[assembly: AssemblyInformationalVersion("3.3.0-alpha.1")] +[assembly: AssemblyVersion("4.0.0")] +[assembly: AssemblyFileVersion("4.0.0")] +[assembly: AssemblyInformationalVersion("4.0.0-alpha.1")] [assembly: AssemblyCopyright("Copyright © WildGums 2010 - 2018")] diff --git a/tools/nuget.exe b/tools/nuget.exe index 4cbab24..7d4cdae 100644 Binary files a/tools/nuget.exe and b/tools/nuget.exe differ