diff --git a/README.md b/README.md index 94d2f0b8e1..0fc577692d 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ chmod +x build.sh So you’re thinking about contributing to Cake? Great! It’s **really** appreciated. -Make sure you've read the [contribution guidelines](http://cakebuild.net/contribute/contribution-guidelines/) before sending that epic pull request. +Make sure you've read the [contribution guidelines](http://cakebuild.net/contribute/contribution-guidelines/) before sending that epic pull request. You'll also need to sign the [contribution license agreement](https://cla2.dotnetfoundation.org/) (CLA) for anything other than a trivial change. **NOTE:** The .Net Foundation CLA Bot will provide a link to this CLA within the PR that you submit if it is deemed as required. * Fork the repository. * Create a branch to work in. @@ -150,6 +150,10 @@ This project has adopted the code of conduct defined by the [Contributor Covenan to clarify expected behavior in our community. For more information see the [.NET Foundation Code of Conduct](http://www.dotnetfoundation.org/code-of-conduct). +## Contribution License Agreement + +By signing the [CLA](https://cla2.dotnetfoundation.org/), the community is free to use your contribution to .NET Foundation projects. + ## .NET Foundation This project is supported by the [.NET Foundation](http://www.dotnetfoundation.org). diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 015967ac19..5fc881d280 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,48 @@ +### New on 0.17.0 (Released 2016/11/09) + +* Allow custom loggers in the VSTestSettings +* Add support for InnoSetup +* Add a "Prepend" extension for the ProcessArgumentBuilder +* Add Support for the Go.CD build provider +* Add GitLab CI build system support +* Add VSTS build system support +* Wait for AppVeyor process to exit +* Add Ability to Redirect Standard Error on IProcess +* Add option to keep the autogenerated NuSpec file +* IsDependentOn with CakeTaskBuilder parameter +* CopyFiles doesn't respect source directory structure +* Add DotCover Report +* Support OctoPack +* Add support for moving directories +* Typo in VSTestSettings extension method name +* Globber exception when using a path with an exclamation +* Error: An item with the same key has already been added while running Cake from commit hooks +* System time separator is used when Octo DeployAt argument is converted to string +* Unquoted VSTest settings file path +* Globber exception when glob contains % +* GetEntryAssembly can return null, leading to NullReferenceException +* NuGetPack fails if no Files have been specified +* Add support fort Specifying Dependencies for Multi Target package +* Support DefaultCredentials usage for Http Downloads +* Add additional parameters to MSBuild runner +* Add Go.CD build history API call +* Some properties for RoundhouseSettings in Cake.Common.Tools.Roundhouse are not working properly +* Add user agent for DownloadFile +* Guard against invalid path environment variables +* Adding all current parameters for VSTest +* OctoCreateRelease is missing channel option +* Option to deploy an existing release in OctopusDeploy +* Get return code from intercepted process in SpecFlow TestExecutionReport +* Add parameter LogFile to DotCover commands +* Can't specify hash algorithm for the Sign command +* MSBuild add log file support +* Support for SHA256 code signing +* Fixed typos 'occured' and 'occuring' +* Add CLA link to README. +* Removed erroneous apostrophes +* Corrects the grammar "do/does" in exception messages and tests +* Adds default CPU count behavior to MSBuild settings documentation + ### New on 0.16.2 (Released 2016/10/11) * Fixed CakeExecuteScript getting access denied errors on mono/m diff --git a/build.ps1 b/build.ps1 index b4f7aac940..0ac5bf9af8 100644 --- a/build.ps1 +++ b/build.ps1 @@ -31,7 +31,7 @@ Param( [string[]]$ScriptArgs ) -$CakeVersion = "0.16.0" +$CakeVersion = "0.16.2" $DotNetChannel = "preview"; $DotNetVersion = "1.0.0-preview2-003121"; $DotNetInstallerUri = "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-preview2/scripts/obtain/dotnet-install.ps1"; diff --git a/build.sh b/build.sh index 312acdda13..4baa60611b 100755 --- a/build.sh +++ b/build.sh @@ -10,7 +10,7 @@ SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TOOLS_DIR=$SCRIPT_DIR/tools NUGET_EXE=$TOOLS_DIR/nuget.exe NUGET_URL=https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -CAKE_VERSION=0.16.0 +CAKE_VERSION=0.16.2 CAKE_EXE=$TOOLS_DIR/Cake.$CAKE_VERSION/Cake.exe # Define default arguments. diff --git a/src/Cake.Common.Tests/Fixtures/Build/GitLabCIFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/GitLabCIFixture.cs new file mode 100644 index 0000000000..ee40d3e306 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/GitLabCIFixture.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI; +using Cake.Core; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class GitLabCIFixture + { + public ICakeEnvironment Environment { get; set; } + + public GitLabCIFixture() + { + Environment = Substitute.For(); + Environment.GetEnvironmentVariable("CI_SERVER").Returns((string)null); + } + + public void IsRunningOnGitLabCI() + { + Environment.GetEnvironmentVariable("CI_SERVER").Returns("yes"); + } + + public GitLabCIProvider CreateGitLabCIService() + { + return new GitLabCIProvider(Environment); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Fixtures/Build/GitLabCIInfoFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/GitLabCIInfoFixture.cs new file mode 100644 index 0000000000..0d8b7eeeee --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/GitLabCIInfoFixture.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI.Data; +using Cake.Core; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class GitLabCIInfoFixture + { + public ICakeEnvironment Environment { get; set; } + + public GitLabCIInfoFixture() + { + Environment = Substitute.For(); + + // Example values taken from https://docs.gitlab.com/ce/ci/variables/README.html + Environment.GetEnvironmentVariable("CI_SERVER").Returns("yes"); + Environment.GetEnvironmentVariable("CI_BUILD_ID").Returns("50"); + Environment.GetEnvironmentVariable("CI_BUILD_REF").Returns("1ecfd275763eff1d6b4844ea3168962458c9f27a"); + Environment.GetEnvironmentVariable("CI_BUILD_REF_NAME").Returns("master"); + Environment.GetEnvironmentVariable("CI_BUILD_REPO").Returns("https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/gitlab-org/gitlab-ce.git"); + Environment.GetEnvironmentVariable("CI_BUILD_TAG").Returns("1.0.0"); + Environment.GetEnvironmentVariable("CI_BUILD_NAME").Returns("spec:other"); + Environment.GetEnvironmentVariable("CI_BUILD_STAGE").Returns("test"); + Environment.GetEnvironmentVariable("CI_BUILD_MANUAL").Returns("true"); + Environment.GetEnvironmentVariable("CI_BUILD_TRIGGERED").Returns("true"); + Environment.GetEnvironmentVariable("CI_BUILD_TOKEN").Returns("abcde-1234ABCD5678ef"); + Environment.GetEnvironmentVariable("CI_PIPELINE_ID").Returns("1000"); + Environment.GetEnvironmentVariable("CI_PROJECT_ID").Returns("34"); + Environment.GetEnvironmentVariable("CI_PROJECT_DIR").Returns("/builds/gitlab-org/gitlab-ce"); + Environment.GetEnvironmentVariable("CI_PROJECT_NAME").Returns("gitlab-ce"); + Environment.GetEnvironmentVariable("CI_PROJECT_NAMESPACE").Returns("gitlab-org"); + Environment.GetEnvironmentVariable("CI_PROJECT_PATH").Returns("gitlab-org/gitlab-ce"); + Environment.GetEnvironmentVariable("CI_PROJECT_URL").Returns("https://gitlab.com/gitlab-org/gitlab-ce"); + Environment.GetEnvironmentVariable("CI_REGISTRY").Returns("registry.gitlab.com"); + Environment.GetEnvironmentVariable("CI_REGISTRY_IMAGE").Returns("registry.gitlab.com/gitlab-org/gitlab-ce"); + Environment.GetEnvironmentVariable("CI_RUNNER_ID").Returns("10"); + Environment.GetEnvironmentVariable("CI_RUNNER_DESCRIPTION").Returns("my runner"); + Environment.GetEnvironmentVariable("CI_RUNNER_TAGS").Returns("docker, linux"); + Environment.GetEnvironmentVariable("CI_SERVER").Returns("yes"); + Environment.GetEnvironmentVariable("CI_SERVER_NAME").Returns("GitLab"); + Environment.GetEnvironmentVariable("CI_SERVER_REVISION").Returns("70606bf"); + Environment.GetEnvironmentVariable("CI_SERVER_VERSION").Returns("8.9.0"); + Environment.GetEnvironmentVariable("GITLAB_USER_ID").Returns("42"); + Environment.GetEnvironmentVariable("GITLAB_USER_EMAIL").Returns("anthony@warwickcontrol.com"); + } + + public GitLabCIBuildInfo CreateBuildInfo() + { + return new GitLabCIBuildInfo(Environment); + } + + public GitLabCIProjectInfo CreateProjectInfo() + { + return new GitLabCIProjectInfo(Environment); + } + + public GitLabCIRunnerInfo CreateRunnerInfo() + { + return new GitLabCIRunnerInfo(Environment); + } + + public GitLabCIServerInfo CreateServerInfo() + { + return new GitLabCIServerInfo(Environment); + } + + public GitLabCIEnvironmentInfo CreateEnvironmentInfo() + { + return new GitLabCIEnvironmentInfo(Environment); + } + } +} diff --git a/src/Cake.Common.Tests/Fixtures/Build/GoCDFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/GoCDFixture.cs new file mode 100644 index 0000000000..eef6bca400 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/GoCDFixture.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GoCD; +using Cake.Core; +using Cake.Testing; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class GoCDFixture + { + public ICakeEnvironment Environment { get; set; } + + public FakeLog CakeLog { get; set; } + + public GoCDFixture() + { + Environment = Substitute.For(); + Environment.GetEnvironmentVariable("https://127.0.0.1:8154/go").Returns((string)null); + CakeLog = new FakeLog(); + } + + public void IsRunningOnGoCD() + { + Environment.GetEnvironmentVariable("GO_SERVER_URL").Returns("https://127.0.0.1:8154/go"); + } + + public GoCDProvider CreateGoCDService() + { + return new GoCDProvider(Environment, CakeLog); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Fixtures/Build/GoCDInfoFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/GoCDInfoFixture.cs new file mode 100644 index 0000000000..79b8a35d07 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/GoCDInfoFixture.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GoCD.Data; +using Cake.Core; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class GoCDInfoFixture + { + public ICakeEnvironment Environment { get; set; } + + public GoCDInfoFixture() + { + Environment = Substitute.For(); + + // GoCDEnvironmentInfo + Environment.GetEnvironmentVariable("GO_SERVER_URL").Returns("https://127.0.0.1:8154/go"); + Environment.GetEnvironmentVariable("GO_ENVIRONMENT_NAME").Returns("Development"); + Environment.GetEnvironmentVariable("GO_JOB_NAME").Returns("linux-firefox"); + Environment.GetEnvironmentVariable("GO_TRIGGER_USER").Returns("changes"); + + // GoCDPipelineInfo + Environment.GetEnvironmentVariable("GO_PIPELINE_NAME").Returns("main"); + Environment.GetEnvironmentVariable("GO_PIPELINE_COUNTER").Returns("2345"); + Environment.GetEnvironmentVariable("GO_PIPELINE_LABEL").Returns("1.1.2345"); + + // GoCDCommitInfo + Environment.GetEnvironmentVariable("bamboo_planRepository_revision").Returns("d4a3a4cb304548450e3cab2ff735f778ffe58d03"); + + // GoCDRepositoryInfo + Environment.GetEnvironmentVariable("GO_REVISION").Returns("123"); + Environment.GetEnvironmentVariable("GO_TO_REVISION").Returns("124"); + Environment.GetEnvironmentVariable("GO_FROM_REVISION").Returns("122"); + + // GoCDStageInfo + Environment.GetEnvironmentVariable("GO_STAGE_NAME").Returns("dev"); + Environment.GetEnvironmentVariable("GO_STAGE_COUNTER").Returns("1"); + } + + public GoCDEnvironmentInfo CreateEnvironmentInfo() + { + return new GoCDEnvironmentInfo(Environment); + } + + public GoCDPipelineInfo CreatePipelineInfo() + { + return new GoCDPipelineInfo(Environment); + } + + public GoCDRepositoryInfo CreateRepositoryInfo() + { + return new GoCDRepositoryInfo(Environment); + } + + public GoCDStageInfo CreateStageInfo() + { + return new GoCDStageInfo(Environment); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Fixtures/Build/TFBuildFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/TFBuildFixture.cs new file mode 100644 index 0000000000..5bbdeffe00 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/TFBuildFixture.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Cake.Common.Build.TFBuild; +using Cake.Core; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class TFBuildFixture + { + public ICakeEnvironment Environment { get; set; } + + public TFBuildFixture() + { + Environment = Substitute.For(); + Environment.WorkingDirectory.Returns("C:\\build\\CAKE-CAKE-JOB1"); + Environment.GetEnvironmentVariable("TF_BUILD").Returns((string)null); + } + + public void IsRunningOnVSTS() + { + Environment.GetEnvironmentVariable("TF_BUILD").Returns("True"); + Environment.GetEnvironmentVariable("AGENT_NAME").Returns("Hosted Agent"); + } + + public void IsRunningOnTFS() + { + Environment.GetEnvironmentVariable("TF_BUILD").Returns("True"); + Environment.GetEnvironmentVariable("AGENT_NAME").Returns("On Premises"); + } + + public TFBuildProvider CreateTFBuildService() + { + return new TFBuildProvider(Environment); + } + } +} diff --git a/src/Cake.Common.Tests/Fixtures/Build/TFBuildInfoFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/TFBuildInfoFixture.cs new file mode 100644 index 0000000000..9ae25eccf2 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/TFBuildInfoFixture.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Cake.Common.Build.TFBuild.Data; +using Cake.Core; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + public sealed class TFBuildInfoFixture + { + public ICakeEnvironment Environment { get; set; } + + public TFBuildInfoFixture() + { + Environment = Substitute.For(); + + // VSTS RepositoryInfo + Environment.GetEnvironmentVariable("BUILD_SOURCEVERSION").Returns("4efbc1ffb993dfbcf024e6a9202865cc0b6d9c50"); + Environment.GetEnvironmentVariable("BUILD_SOURCETFVCSHELVESET").Returns("Shelveset1"); + Environment.GetEnvironmentVariable("BUILD_REPOSITORY_NAME").Returns("cake"); + Environment.GetEnvironmentVariable("BUILD_REPOSITORY_PROVIDER").Returns("GitHub"); + Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCHNAME").Returns("develop"); + + // VSTS AgentInfo + Environment.GetEnvironmentVariable("AGENT_BUILDDIRECTORY").Returns(@"c:\agent\_work\1"); + Environment.GetEnvironmentVariable("AGENT_HOMEDIRECTORY").Returns(@"c:\agent"); + Environment.GetEnvironmentVariable("AGENT_WORKFOLDER").Returns(@"c:\agent\_work"); + Environment.GetEnvironmentVariable("AGENT_ID").Returns("71"); + Environment.GetEnvironmentVariable("AGENT_NAME").Returns("Agent-1"); + Environment.GetEnvironmentVariable("AGENT_MACHINE_NAME").Returns("BuildServer"); + + // VSTS BuildInfo + Environment.GetEnvironmentVariable("BUILD_BUILDID").Returns("100234"); + Environment.GetEnvironmentVariable("BUILD_BUILDNUMBER").Returns("Build-20160927.1"); + Environment.GetEnvironmentVariable("BUILD_BUILDURI").Returns("vstfs:///Build/Build/1430"); + Environment.GetEnvironmentVariable("BUILD_QUEUEDBY") + .Returns(@"[DefaultCollection]\Project Collection Service Accounts"); + Environment.GetEnvironmentVariable("BUILD_REQUESTEDFOR").Returns("Alistair Chapman"); + Environment.GetEnvironmentVariable("BUILD_REQUESTEDFOREMAIL").Returns("author@mail.com"); + + // VSTS DefinitionInfo + Environment.GetEnvironmentVariable("SYSTEM_DEFINITIONID").Returns("1855"); + Environment.GetEnvironmentVariable("BUILD_DEFINITIONNAME").Returns("Cake-CI"); + Environment.GetEnvironmentVariable("BUILD_DEFINITIONVERSION").Returns("47"); + + // VSTS TeamProjectInfo + Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECT").Returns("TeamProject"); + Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECTID").Returns("D0A3B6B8-499B-4D4B-BD46-DB70C19E6D33"); + Environment.GetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI") + .Returns("https://fabrikamfiber.visualstudio.com/"); + } + + public TFBuildEnvironmentInfo CreateEnvironmentInfo() + { + return new TFBuildEnvironmentInfo(Environment); + } + + public TFBuildRepositoryInfo CreateRepositoryInfo() + { + return new TFBuildRepositoryInfo(Environment); + } + + public TFBuildRepositoryInfo CreateRepositoryInfo(string repoType) + { + Environment.GetEnvironmentVariable("BUILD_REPOSITORY_PROVIDER").Returns(repoType); + return CreateRepositoryInfo(); + } + + public TFBuildAgentInfo CreateAgentInfo() + { + return new TFBuildAgentInfo(Environment); + } + + public TFBuildAgentInfo CreateHostedAgentInfo() + { + Environment.GetEnvironmentVariable("AGENT_NAME").Returns("Hosted Agent"); + return new TFBuildAgentInfo(Environment); + } + + public TFBuildInfo CreateBuildInfo() + { + return new TFBuildInfo(Environment); + } + + public TFBuildDefinitionInfo CreateDefinitionInfo() + { + return new TFBuildDefinitionInfo(Environment); + } + + public TFBuildTeamProjectInfo CreateTeamProjectInfo() + { + return new TFBuildTeamProjectInfo(Environment); + } + } +} diff --git a/src/Cake.Common.Tests/Fixtures/Tools/DotCover/Report/DotCoverReporterFixture.cs b/src/Cake.Common.Tests/Fixtures/Tools/DotCover/Report/DotCoverReporterFixture.cs new file mode 100644 index 0000000000..b075379c78 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Tools/DotCover/Report/DotCoverReporterFixture.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Common.Tools.DotCover.Report; +using Cake.Core; +using Cake.Core.Diagnostics; +using Cake.Core.IO; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Tools.DotCover.Report +{ + internal sealed class DotCoverReporterFixture : DotCoverFixture + { + public FilePath SourceFile { get; set; } + public FilePath OutputFile { get; set; } + + public DotCoverReporterFixture() + { + // Set the source file. + SourceFile = new FilePath("./result.dcvr"); + + // Setup the output file. + OutputFile = new FilePath("./result.xml"); + } + + protected override void RunTool() + { + var tool = new DotCoverReporter(FileSystem, Environment, ProcessRunner, Tools); + tool.Report(SourceFile, OutputFile, Settings); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Fixtures/Tools/InnoSetupFixture.cs b/src/Cake.Common.Tests/Fixtures/Tools/InnoSetupFixture.cs new file mode 100644 index 0000000000..3f6596472d --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Tools/InnoSetupFixture.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.InnoSetup; +using Cake.Core.IO; +using Cake.Testing; +using Cake.Testing.Fixtures; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Tools +{ + internal sealed class InnoSetupFixture : ToolFixture + { + public IRegistry Registry { get; set; } + + public FilePath ScriptPath { get; set; } + + public FilePath InstalledToolPath { get; private set; } + + public InnoSetupFixture() + : base("iscc.exe") + { + ScriptPath = new FilePath("./Test.iss"); + Registry = Substitute.For(); + } + + public void GivenToolIsInstalledX86() + { + ConfigureInstalledLocation(false); + } + + public void GivenToolIsInstalledX64() + { + ConfigureInstalledLocation(true); + } + + private void ConfigureInstalledLocation(bool is64Bit) + { + string registryKeyPath = is64Bit + ? @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 5_is1" + : @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 5_is1"; + + DirectoryPath installLocation = is64Bit + ? "/programfiles(x86)/innosetup" + : "/programfiles/innosetup"; + + InstalledToolPath = installLocation.CombineWithFilePath("iscc.exe"); + + var innoSetupKey = Substitute.For(); + innoSetupKey.GetValue("InstallLocation").Returns(installLocation.FullPath); + + var hklm = Substitute.For(); + hklm.OpenKey(registryKeyPath).Returns(innoSetupKey); + + Registry.LocalMachine.Returns(hklm); + + FileSystem.CreateDirectory(installLocation); + FileSystem.CreateFile(InstalledToolPath); + + Environment.Platform.Is64Bit = is64Bit; + } + + protected override void RunTool() + { + var tool = new InnoSetupRunner(FileSystem, Registry, Environment, ProcessRunner, Tools); + tool.Run(ScriptPath, Settings); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Fixtures/Tools/OctopusDeployPackerFixture.cs b/src/Cake.Common.Tests/Fixtures/Tools/OctopusDeployPackerFixture.cs new file mode 100644 index 0000000000..e31fd4f8bb --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Tools/OctopusDeployPackerFixture.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.OctopusDeploy; +using Cake.Testing.Fixtures; + +namespace Cake.Common.Tests.Fixtures.Tools +{ + internal sealed class OctopusDeployPackerFixture : ToolFixture + { + public string Id { get; set; } + + public OctopusDeployPackerFixture() + : base("octo.exe") + { + } + + protected override void RunTool() + { + var tool = new OctopusDeployPacker(FileSystem, Environment, ProcessRunner, Tools); + tool.Pack(Id, Settings); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Fixtures/Tools/OctopusDeployReleaseDeployerFixture.cs b/src/Cake.Common.Tests/Fixtures/Tools/OctopusDeployReleaseDeployerFixture.cs new file mode 100644 index 0000000000..96ee239955 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Tools/OctopusDeployReleaseDeployerFixture.cs @@ -0,0 +1,34 @@ +using System; +using Cake.Common.Tools.OctopusDeploy; +using Cake.Testing.Fixtures; + +namespace Cake.Common.Tests.Fixtures.Tools +{ + public sealed class OctopusDeployReleaseDeployerFixture : ToolFixture + { + internal string Server { get; set; } + + internal string ApiKey { get; set; } + + internal string Project { get; set; } + + internal string DeployTo { get; set; } + + internal string ReleaseNumber { get; set; } + + public OctopusDeployReleaseDeployerFixture() : base("Octo.exe") + { + Server = "http://octopus"; + ApiKey = "API-12345"; + Project = "MyProject"; + DeployTo = "Testing"; + ReleaseNumber = "0.15.1"; + } + + protected override void RunTool() + { + var tool = new OctopusDeployReleaseDeployer(FileSystem, Environment, ProcessRunner, Tools); + tool.DeployRelease(Server, ApiKey, Project, DeployTo, ReleaseNumber, Settings); + } + } +} diff --git a/src/Cake.Common.Tests/Properties/Resources.Designer.cs b/src/Cake.Common.Tests/Properties/Resources.Designer.cs index 9f724def56..4816f39583 100644 --- a/src/Cake.Common.Tests/Properties/Resources.Designer.cs +++ b/src/Cake.Common.Tests/Properties/Resources.Designer.cs @@ -11,33 +11,31 @@ namespace Cake.Common.Tests.Properties { using System; using System.Reflection; - - + + /// - /// A strongly-typed resource class, for looking up localized strings, etc. + /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { + public class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// - /// Returns the cached ResourceManager instance used by this class. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Cake.Common.Tests.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); @@ -48,11 +46,11 @@ internal Resources() { } /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { + public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -62,7 +60,7 @@ internal Resources() { } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. --> ///<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> /// <metadata> @@ -73,14 +71,14 @@ internal Resources() { /// <owners>Owner #1,Owner #2</owners> /// <summary>The summa [rest of string was truncated]";. /// - internal static string ChocolateyNuspec_Metadata { + public static string ChocolateyNuspec_Metadata { get { return ResourceManager.GetString("ChocolateyNuspec_Metadata", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. --> ///<package> /// <metadata> @@ -93,14 +91,14 @@ internal static string ChocolateyNuspec_Metadata { /// <description>The description</description> /// [rest of string was truncated]";. /// - internal static string ChocolateyNuspec_Metadata_WithoutNamespaces { + public static string ChocolateyNuspec_Metadata_WithoutNamespaces { get { return ResourceManager.GetString("ChocolateyNuspec_Metadata_WithoutNamespaces", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. --> ///<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> /// <files> @@ -108,14 +106,14 @@ internal static string ChocolateyNuspec_Metadata_WithoutNamespaces { /// </files> ///</package>. /// - internal static string ChocolateyNuspec_NoMetadataElement { + public static string ChocolateyNuspec_NoMetadataElement { get { return ResourceManager.GetString("ChocolateyNuspec_NoMetadataElement", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. --> ///<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> /// <metadata /> @@ -124,14 +122,14 @@ internal static string ChocolateyNuspec_NoMetadataElement { /// </files> ///</package>. /// - internal static string ChocolateyNuspec_NoMetadataValues { + public static string ChocolateyNuspec_NoMetadataValues { get { return ResourceManager.GetString("ChocolateyNuspec_NoMetadataValues", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. --> ///<package> /// <metadata /> @@ -140,42 +138,42 @@ internal static string ChocolateyNuspec_NoMetadataValues { /// </files> ///</package>. /// - internal static string ChocolateyNuspec_NoMetadataValues_WithoutNamespaces { + public static string ChocolateyNuspec_NoMetadataValues_WithoutNamespaces { get { return ResourceManager.GetString("ChocolateyNuspec_NoMetadataValues_WithoutNamespaces", resourceCulture); } } /// - /// Looks up a localized string similar to <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + /// Looks up a localized string similar to <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> /// <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> /// <PropertyGroup> /// <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion> /// <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> /// <Platform Condition=" '$(Platform)' == [rest of string was truncated]";. /// - internal static string Csproj_IncompleteFile { + public static string Csproj_IncompleteFile { get { return ResourceManager.GetString("Csproj_IncompleteFile", resourceCulture); } } /// - /// Looks up a localized string similar to <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + /// Looks up a localized string similar to <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> /// <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> /// <PropertyGroup> /// <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion> /// <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> /// <Platform Condition=" '$(Platform)' == [rest of string was truncated]";. /// - internal static string Csproj_ProjectFile { + public static string Csproj_ProjectFile { get { return ResourceManager.GetString("Csproj_ProjectFile", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<DuplicatesReport ToolsVersion="103.0"> /// <Statistics> /// <CodebaseCost>190358</CodebaseCost> @@ -185,14 +183,14 @@ internal static string Csproj_ProjectFile { /// <Duplicates></Duplicates> ///</DuplicatesReport>. /// - internal static string DupFinderReportNoDuplicates { + public static string DupFinderReportNoDuplicates { get { return ResourceManager.GetString("DupFinderReportNoDuplicates", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<DuplicatesReport ToolsVersion="103.0"> /// <Statistics> /// <CodebaseCost>190358</CodebaseCost> @@ -209,14 +207,14 @@ internal static string DupFinderReportNoDuplicates { /// <Fragment> /// <FileName>LangFe [rest of string was truncated]";. /// - internal static string DupFinderReportWithDuplicates { + public static string DupFinderReportWithDuplicates { get { return ResourceManager.GetString("DupFinderReportWithDuplicates", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Generated by InspectCode 8.2.1000.4527 --> ///<Report ToolsVersion="8.2"> /// <Information> @@ -229,14 +227,14 @@ internal static string DupFinderReportWithDuplicates { /// <Issues></Issues> ///</Report>. /// - internal static string InspectCodeReportNoViolations { + public static string InspectCodeReportNoViolations { get { return ResourceManager.GetString("InspectCodeReportNoViolations", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<!-- Generated by InspectCode 8.2.1000.4527 --> ///<Report ToolsVersion="8.2"> /// <Information> @@ -252,14 +250,14 @@ internal static string InspectCodeReportNoViolations { /// <Project Name="Cake.Common"> /// <Issue TypeId="CSharpErrors" File="Cake.Common.Tests\F [rest of string was truncated]";. /// - internal static string InspectCodeReportWithViolations { + public static string InspectCodeReportWithViolations { get { return ResourceManager.GetString("InspectCodeReportWithViolations", resourceCulture); } } /// - /// Looks up a localized string similar to using System.Reflection; + /// Looks up a localized string similar to using System.Reflection; ///using System.Runtime.CompilerServices; /// ///// Information about this assembly is defined by the following attributes. @@ -272,14 +270,14 @@ internal static string InspectCodeReportWithViolations { ///[assembly: AssemblyProduct ("MonoDevelopProduct")] ///[assembly: Assembl [rest of string was truncated]";. /// - internal static string MonoDevelopAssemblyInfo { + public static string MonoDevelopAssemblyInfo { get { return ResourceManager.GetString("MonoDevelopAssemblyInfo", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> /// <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> /// <id>The ID</id> @@ -291,14 +289,14 @@ internal static string MonoDevelopAssemblyInfo { /// <summary>The summary</summary> /// <licenseUrl>https://lic [rest of string was truncated]";. /// - internal static string Nuspec_Metadata { + public static string Nuspec_Metadata { get { return ResourceManager.GetString("Nuspec_Metadata", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> /// <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> /// <id>The ID</id> @@ -310,14 +308,14 @@ internal static string Nuspec_Metadata { /// <summary>The summary</summary> /// <licenseUrl>https://lic [rest of string was truncated]";. /// - internal static string Nuspec_Metadata_WithDependencies { + public static string Nuspec_Metadata_WithDependencies { get { return ResourceManager.GetString("Nuspec_Metadata_WithDependencies", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package> /// <metadata> /// <id>The ID</id> @@ -332,14 +330,14 @@ internal static string Nuspec_Metadata_WithDependencies { /// <iconUrl>https://icon.com</iconUrl> /// <developmentDependency>true</developmentDepende [rest of string was truncated]";. /// - internal static string Nuspec_Metadata_WithoutNamespaces { + public static string Nuspec_Metadata_WithoutNamespaces { get { return ResourceManager.GetString("Nuspec_Metadata_WithoutNamespaces", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package> /// <metadata> /// <id>The ID</id> @@ -354,14 +352,73 @@ internal static string Nuspec_Metadata_WithoutNamespaces { /// <iconUrl>https://icon.com</iconUrl> /// <developmentDependency>true</developmentDepende [rest of string was truncated]";. /// - internal static string Nuspec_Metadata_WithoutNamespaces_WithDependencies { + public static string Nuspec_Metadata_WithoutNamespaces_WithDependencies { get { return ResourceManager.GetString("Nuspec_Metadata_WithoutNamespaces_WithDependencies", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + ///<package> + /// <metadata> + /// <id>The ID</id> + /// <version>The version</version> + /// <title>The title</title> + /// <authors>Author #1,Author #2</authors> + /// <owners>Owner #1,Owner #2</owners> + /// <description>The description</description> + /// <summary>The summary</summary> + /// <licenseUrl>https://license.com</licenseUrl> + /// <projectUrl>https://project.com</projectUrl> + /// <iconUrl>https://icon.com</iconUrl> + /// <developmentDependency>true</developmentDepende [rest of string was truncated]";. + /// + public static string Nuspec_Metadata_WithoutNamespaces_WithTargetFramworkDependencies { + get { + return ResourceManager.GetString("Nuspec_Metadata_WithoutNamespaces_WithTargetFramworkDependencies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + ///<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + /// <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> + /// <id>nonexisting</id> + /// <version>1.0.0</version> + /// <authors>Author #1,Author #2</authors> + /// <description>The description</description> + /// <developmentDependency>false</developmentDependency> + /// <requireLicenseAcceptance>false</requireLicenseAcceptance> + /// <depende [rest of string was truncated]";. + /// + public static string Nuspec_Metadata_WithTargetFrameworkDependencies { + get { + return ResourceManager.GetString("Nuspec_Metadata_WithTargetFrameworkDependencies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + ///<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + /// <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> + /// <id>The ID</id> + /// <version>The version</version> + /// <title>The title</title> + /// <authors>Author #1,Author #2</authors> + /// <owners>Owner #1,Owner #2</owners> + /// <description>The description</description> + /// <summary>The summary</summary> + /// <licenseUrl>https://lic [rest of string was truncated]";. + /// + public static string Nuspec_Metadata_WithTragetFramworkDependencies { + get { + return ResourceManager.GetString("Nuspec_Metadata_WithTragetFramworkDependencies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> /// <files> /// <file src="Cake.Core.dll" target="lib/net45" /> @@ -371,14 +428,14 @@ internal static string Nuspec_Metadata_WithoutNamespaces_WithDependencies { /// </files> ///</package>. /// - internal static string Nuspec_NoMetadataElement { + public static string Nuspec_NoMetadataElement { get { return ResourceManager.GetString("Nuspec_NoMetadataElement", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> /// <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd" /> /// <files> @@ -389,14 +446,14 @@ internal static string Nuspec_NoMetadataElement { /// </files> ///</package>. /// - internal static string Nuspec_NoMetadataValues { + public static string Nuspec_NoMetadataValues { get { return ResourceManager.GetString("Nuspec_NoMetadataValues", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<package> /// <metadata /> /// <files> @@ -407,14 +464,14 @@ internal static string Nuspec_NoMetadataValues { /// </files> ///</package>. /// - internal static string Nuspec_NoMetadataValues_WithoutNamespaces { + public static string Nuspec_NoMetadataValues_WithoutNamespaces { get { return ResourceManager.GetString("Nuspec_NoMetadataValues_WithoutNamespaces", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> ///<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> /// <PropertyGroup> /// <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> @@ -424,14 +481,31 @@ internal static string Nuspec_NoMetadataValues_WithoutNamespaces { /// <ProjectGuid>{AE8E29D0-6FF2-42D0-94EC-E725276A864D}</ProjectGuid> /// <OutputType>Library</OutputTy [rest of string was truncated]";. /// - internal static string Nuspec_ProjectFile { + public static string Nuspec_ProjectFile { get { return ResourceManager.GetString("Nuspec_ProjectFile", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Microsoft Visual Studio Solution File, Format Version 12.00 + ///# Visual Studio 14 + ///VisualStudioVersion = 14.0.25123.0 + ///MinimumVisualStudioVersion = 10.0.40219.1 + ///Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2400A22B-695E-4BDF-93CB-8757F5FB3FB7}" + ///EndProject + ///Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{69930DD1-1688-4407-B4AB-B9E2C0BFB284}" + ///EndProject + ///Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dummy", "src\dummy\dummy.csproj", "{ADCB37DA-2469-462F-99 [rest of string was truncated]";. + /// + public static string Solution_WithProjectsAndFolders { + get { + return ResourceManager.GetString("Solution_WithProjectsAndFolders", resourceCulture); + } + } + /// - /// Looks up a localized string similar to using System.Reflection; + /// Looks up a localized string similar to using System.Reflection; ///using System.Runtime.CompilerServices; /// ///// Information about this assembly is defined by the following attributes. @@ -444,30 +518,14 @@ internal static string Nuspec_ProjectFile { ///[assembly: AssemblyProduct("VisualStudioProduct")] ///[assembly: Assembl [rest of string was truncated]";. /// - internal static string VisualStudioAssemblyInfo - { - get { return ResourceManager.GetString("VisualStudioAssemblyInfo", resourceCulture); } - } - - /// - /// Looks up a localized string similar to Microsoft Visual Studio Solution File, Format Version 12.00 - ///# Visual Studio 14 - ///VisualStudioVersion = 14.0.25123.0 - ///MinimumVisualStudioVersion = 10.0.40219.1 - ///Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2400A22B-695E-4BDF-93CB-8757F5FB3FB7}" - ///EndProject - ///Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{69930DD1-1688-4407-B4AB-B9E2C0BFB284}" - ///EndProject - ///Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dummy", "src\dummy\dummy.csproj", "{ADCB37DA-2469-462F-99 [rest of string was truncated]";. - /// - internal static string Solution_WithProjectsAndFolders { + public static string VisualStudioAssemblyInfo { get { - return ResourceManager.GetString("Solution_WithProjectsAndFolders", resourceCulture); + return ResourceManager.GetString("VisualStudioAssemblyInfo", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0"?> + /// Looks up a localized string similar to <?xml version="1.0"?> ///<doc> /// <assembly> /// <name>Cake.Common</name> @@ -481,14 +539,14 @@ internal static string Solution_WithProjectsAndFolders { /// <param name="projectPath">The project file path.</param> /// <returns>A parsed project.< [rest of string was truncated]";. /// - internal static string XmlDoc_ExampeCode_Cake_Common_Xml { + public static string XmlDoc_ExampeCode_Cake_Common_Xml { get { return ResourceManager.GetString("XmlDoc_ExampeCode_Cake_Common_Xml", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> ///<configuration> /// <appSettings> /// <add key="server" value="testhost.somecompany.com" /> @@ -498,14 +556,14 @@ internal static string XmlDoc_ExampeCode_Cake_Common_Xml { ///</configuration> ///. /// - internal static string XmlPeek_Xml { + public static string XmlPeek_Xml { get { return ResourceManager.GetString("XmlPeek_Xml", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> ///<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> ///<plist version="1.0"> ///<dict> @@ -515,14 +573,14 @@ internal static string XmlPeek_Xml { ///</plist> /// . /// - internal static string XmlPeek_Xml_Dtd { + public static string XmlPeek_Xml_Dtd { get { return ResourceManager.GetString("XmlPeek_Xml_Dtd", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> ///<configuration> /// <appSettings> /// <add key="server" value="testhost.somecompany.com" /> @@ -530,14 +588,14 @@ internal static string XmlPeek_Xml_Dtd { /// </appSettings> ///</configuration>. /// - internal static string XmlPoke_Xml { + public static string XmlPoke_Xml { get { return ResourceManager.GetString("XmlPoke_Xml", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> ///<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> ///<plist version="1.0"> ///<dict> @@ -547,28 +605,28 @@ internal static string XmlPoke_Xml { ///</plist> /// . /// - internal static string XmlPoke_Xml_Dtd { + public static string XmlPoke_Xml_Dtd { get { return ResourceManager.GetString("XmlPoke_Xml_Dtd", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?><html><body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"><div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Belgian Waffles + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?><html><body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"><div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Belgian Waffles /// - /// </span>$5.95</div><div style="margin-left:20px;margin-bottom:1em;font-size:10pt"><p>Two of our famous Belgian Waffles with plenty of real maple syrup<span style="font-style:italic"> /// ( /// 650 /// [rest of string was truncated]";. /// - internal static string XmlTransformation_Htm { + public static string XmlTransformation_Htm { get { return ResourceManager.GetString("XmlTransformation_Htm", resourceCulture); } } /// - /// Looks up a localized string similar to <html><body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"><div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Belgian Waffles + /// Looks up a localized string similar to <html><body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"><div style="background-color:teal;color:white;padding:4px"><span style="font-weight:bold">Belgian Waffles /// - /// </span>$5.95</div><div style="margin-left:20px;margin-bottom:1em;font-size:10pt"><p>Two of our famous Belgian Waffles with plenty of real maple syrup<span style="font-style:italic"> /// ( @@ -576,14 +634,14 @@ internal static string XmlTransformation_Htm { /// calories per serving) /// [rest of string was truncated]";. /// - internal static string XmlTransformation_Htm_NoXmlDeclaration { + public static string XmlTransformation_Htm_NoXmlDeclaration { get { return ResourceManager.GetString("XmlTransformation_Htm_NoXmlDeclaration", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> ///<breakfast_menu> /// <food> /// <name>Belgian Waffles</name> @@ -597,14 +655,14 @@ internal static string XmlTransformation_Htm_NoXmlDeclaration { /// <description>Light Belgian waffles covered with strawberries and whipped cream</description> /// <calories>900</calories> [rest of string was truncated]";. /// - internal static string XmlTransformation_Xml { + public static string XmlTransformation_Xml { get { return ResourceManager.GetString("XmlTransformation_Xml", resourceCulture); } } /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> ///<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0"> /// <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"> /// <xsl:for-each select="breakfast_menu/food"> @@ -615,7 +673,7 @@ internal static string XmlTransformation_Xml { /// </span> /// <xsl:value-of select="price" [rest of string was truncated]";. /// - internal static string XmlTransformation_Xsl { + public static string XmlTransformation_Xsl { get { return ResourceManager.GetString("XmlTransformation_Xsl", resourceCulture); } diff --git a/src/Cake.Common.Tests/Properties/Resources.resx b/src/Cake.Common.Tests/Properties/Resources.resx index 1a056ee6a9..08ff907ab7 100644 --- a/src/Cake.Common.Tests/Properties/Resources.resx +++ b/src/Cake.Common.Tests/Properties/Resources.resx @@ -879,4 +879,103 @@ Global EndGlobalSection EndGlobal + + <?xml version="1.0" encoding="utf-8"?> +<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> + <id>nonexisting</id> + <version>1.0.0</version> + <authors>Author #1,Author #2</authors> + <description>The description</description> + <developmentDependency>false</developmentDependency> + <requireLicenseAcceptance>false</requireLicenseAcceptance> + <dependencies> + <group targetFramework="net452"> + <dependency id="Test1" version="1.0.0" /> + </group> + <group targetFramework="net462"> + <dependency id="Test1" version="1.0.0" /> + </group> + </dependencies> + </metadata> + <files> + </files> +</package> + + + <?xml version="1.0" encoding="utf-8"?> +<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> + <id>The ID</id> + <version>The version</version> + <title>The title</title> + <authors>Author #1,Author #2</authors> + <owners>Owner #1,Owner #2</owners> + <description>The description</description> + <summary>The summary</summary> + <licenseUrl>https://license.com</licenseUrl> + <projectUrl>https://project.com</projectUrl> + <iconUrl>https://icon.com</iconUrl> + <developmentDependency>true</developmentDependency> + <requireLicenseAcceptance>true</requireLicenseAcceptance> + <copyright>The copyright</copyright> + <releaseNotes><![CDATA[Line #1 +Line #2 +Line #3]]></releaseNotes> + <tags>Tag1 Tag2 Tag3</tags> + <dependencies> + <group targetFramework="net452"> + <dependency id="Test1" version="1.0.0" /> + </group> + <group targetFramework="net462"> + <dependency id="Test2" version="[1.0.0]" /> + </group> + </dependencies> + </metadata> + <files> + <file src="Cake.Core.dll" target="lib/net45" /> + <file src="Cake.Core.xml" target="lib/net45" /> + <file src="Cake.Core.pdb" target="lib/net45" /> + <file src="LICENSE" /> + </files> +</package> + + + <?xml version="1.0" encoding="utf-8"?> +<package> + <metadata> + <id>The ID</id> + <version>The version</version> + <title>The title</title> + <authors>Author #1,Author #2</authors> + <owners>Owner #1,Owner #2</owners> + <description>The description</description> + <summary>The summary</summary> + <licenseUrl>https://license.com</licenseUrl> + <projectUrl>https://project.com</projectUrl> + <iconUrl>https://icon.com</iconUrl> + <developmentDependency>true</developmentDependency> + <requireLicenseAcceptance>true</requireLicenseAcceptance> + <copyright>The copyright</copyright> + <releaseNotes><![CDATA[Line #1 +Line #2 +Line #3]]></releaseNotes> + <tags>Tag1 Tag2 Tag3</tags> + <dependencies> + <group targetFramework="net452"> + <dependency id="Test1" version="1.0.0" /> + </group> + <group targetFramework="net462"> + <dependency id="Test2" version="[1.0.0]" /> + </group> + </dependencies> + </metadata> + <files> + <file src="Cake.Core.dll" target="lib/net45" /> + <file src="Cake.Core.xml" target="lib/net45" /> + <file src="Cake.Core.pdb" target="lib/net45" /> + <file src="LICENSE" /> + </files> +</package> + \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/BuildSystemAliasesTests.cs b/src/Cake.Common.Tests/Unit/Build/BuildSystemAliasesTests.cs index 4bc946cc15..5118e61a58 100644 --- a/src/Cake.Common.Tests/Unit/Build/BuildSystemAliasesTests.cs +++ b/src/Cake.Common.Tests/Unit/Build/BuildSystemAliasesTests.cs @@ -109,5 +109,31 @@ public void Should_Throw_If_Context_Is_Null() Assert.IsArgumentNullException(result, "context"); } } + + public sealed class TheGitLabCIMethod + { + [Fact] + public void Should_Throw_If_Context_Is_Null() + { + // Given, When + var result = Record.Exception(() => BuildSystemAliases.GitLabCI(null)); + + // Then + Assert.IsArgumentNullException(result, "context"); + } + } + + public sealed class TheTFBuildMethod + { + [Fact] + public void Should_Throw_If_Context_Is_Null() + { + // Given, When + var result = Record.Exception(() => BuildSystemAliases.TFBuild(null)); + + // Then + Assert.IsArgumentNullException(result, "context"); + } + } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs b/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs index 3d37d7184b..0aa6aba1f4 100644 --- a/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs +++ b/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs @@ -8,9 +8,12 @@ using Cake.Common.Build.BitbucketPipelines; using Cake.Common.Build.Bitrise; using Cake.Common.Build.ContinuaCI; +using Cake.Common.Build.GitLabCI; +using Cake.Common.Build.GoCD; using Cake.Common.Build.Jenkins; using Cake.Common.Build.MyGet; using Cake.Common.Build.TeamCity; +using Cake.Common.Build.TFBuild; using Cake.Common.Build.TravisCI; using NSubstitute; using Xunit; @@ -33,9 +36,12 @@ public void Should_Throw_If_AppVeyor_Is_Null() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(null, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(null, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "appVeyorProvider"); @@ -53,9 +59,12 @@ public void Should_Throw_If_TeamCity_Is_Null() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, null, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, null, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "teamCityProvider"); @@ -73,9 +82,12 @@ public void Should_Throw_If_MyGet_Is_Null() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, null, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, null, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "myGetProvider"); @@ -93,9 +105,12 @@ public void Should_Throw_If_Bamboo_Is_Null() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, null, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, null, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "bambooProvider"); @@ -113,9 +128,12 @@ public void Should_Throw_If_ContinuaCI_Is_Null() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, null, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, null, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "continuaCIProvider"); @@ -133,9 +151,12 @@ public void Should_Throw_If_Jenkins_Is_Null() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, null, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, null, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "jenkinsProvider"); @@ -153,9 +174,12 @@ public void Should_Throw_If_Bitrise_Is_Null() var jenkinsProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, null, travisCIProvider, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, null, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "bitriseProvider"); @@ -173,9 +197,12 @@ public void Should_Throw_If_TravisCI_Is_Null() var jenkinsProvider = Substitute.For(); var bitriseProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, null, bitbucketPipelinesProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, null, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "travisCIProvider"); @@ -193,13 +220,85 @@ public void Should_Throw_If_BitbucketPipelines_Is_Null() var jenkinsProvider = Substitute.For(); var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, null)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, null, goCDProvider, gitlabCIProvider, tfBuildProvider)); // Then Assert.IsArgumentNullException(result, "bitbucketPipelinesProvider"); } + + [Fact] + public void Should_Throw_If_GoCD_Is_Null() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + // When + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, null, gitlabCIProvider, tfBuildProvider)); + + // Then + Assert.IsArgumentNullException(result, "goCDProvider"); + } + + [Fact] + public void Should_Throw_If_GitLabCI_Is_Null() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + // When + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, null, tfBuildProvider)); + + // Then + Assert.IsArgumentNullException(result, "gitlabCIProvider"); + } + + [Fact] + public void Should_Throw_If_TFBuild_Is_Null() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + + // When + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, null)); + + // Then + Assert.IsArgumentNullException(result, "tfBuildProvider"); + } } public sealed class TheIsRunningOnAppVeyorProperty @@ -217,9 +316,12 @@ public void Should_Return_True_If_Running_On_AppVeyor() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnAppVeyor; @@ -244,9 +346,12 @@ public void Should_Return_True_If_Running_On_TeamCity() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); teamCityProvider.IsRunningOnTeamCity.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnTeamCity; @@ -271,9 +376,12 @@ public void Should_Return_True_If_Running_On_MyGet() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); myGetProvider.IsRunningOnMyGet.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnMyGet; @@ -298,9 +406,12 @@ public void Should_Return_True_If_Running_On_Bamboo() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); bambooProvider.IsRunningOnBamboo.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnBamboo; @@ -325,9 +436,12 @@ public void Should_Return_True_If_Running_On_ContinuaCI() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); continuaCIProvider.IsRunningOnContinuaCI.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnContinuaCI; @@ -352,9 +466,12 @@ public void Should_Return_True_If_Running_On_Jenkins() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); jenkinsProvider.IsRunningOnJenkins.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnJenkins; @@ -379,9 +496,12 @@ public void Should_Return_True_If_Running_On_Bitrise() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); bitriseProvider.IsRunningOnBitrise.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnBitrise; @@ -406,9 +526,12 @@ public void Should_Return_True_If_Running_On_TravisCI() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); travisCIProvider.IsRunningOnTravisCI.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnTravisCI; @@ -433,9 +556,12 @@ public void Should_Return_True_If_Running_On_BitbucketPipelines() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsRunningOnBitbucketPipelines; @@ -445,6 +571,126 @@ public void Should_Return_True_If_Running_On_BitbucketPipelines() } } + public sealed class TheIsRunningOnGoCDProperty + { + [Fact] + public void Should_Return_True_If_Running_On_GoCD() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + goCDProvider.IsRunningOnGoCD.Returns(true); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsRunningOnGoCD; + + // Then + Assert.True(result); + } + } + + public sealed class TheIsRunningOnGitLabCIProperty + { + [Fact] + public void Should_Return_True_If_Running_On_GitLabCI() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + gitlabCIProvider.IsRunningOnGitLabCI.Returns(true); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsRunningOnGitLabCI; + + // Then + Assert.True(result); + } + } + + public sealed class TheIsRunningOnVSTSProperty + { + [Fact] + public void Should_Return_True_If_Running_On_VSTS() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + tfBuildProvider.IsRunningOnVSTS.Returns(true); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsRunningOnVSTS; + + // Then + Assert.True(result); + } + } + + public sealed class TheIsRunningOnTFSProperty + { + [Fact] + public void Should_Return_True_If_Running_On_TFS() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + tfBuildProvider.IsRunningOnTFS.Returns(true); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsRunningOnTFS; + + // Then + Assert.True(result); + } + } + public sealed class TheIsLocalBuildProperty { [Fact] @@ -460,6 +706,9 @@ public void Should_Return_False_If_Running_On_AppVeyor() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(true); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -470,7 +719,10 @@ public void Should_Return_False_If_Running_On_AppVeyor() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -492,6 +744,9 @@ public void Should_Return_False_If_Running_On_TeamCity() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(true); @@ -502,7 +757,10 @@ public void Should_Return_False_If_Running_On_TeamCity() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -524,6 +782,9 @@ public void Should_Return_False_If_Running_On_MyGet() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -534,7 +795,10 @@ public void Should_Return_False_If_Running_On_MyGet() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -556,6 +820,9 @@ public void Should_Return_False_If_Running_On_Bamboo() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -566,7 +833,10 @@ public void Should_Return_False_If_Running_On_Bamboo() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -588,6 +858,9 @@ public void Should_Return_False_If_Running_On_ContinuaCI() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -598,7 +871,10 @@ public void Should_Return_False_If_Running_On_ContinuaCI() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -620,6 +896,9 @@ public void Should_Return_False_If_Running_On_Jenkins() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -630,7 +909,10 @@ public void Should_Return_False_If_Running_On_Jenkins() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -652,6 +934,9 @@ public void Should_Return_False_If_Running_On_Bitrise() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -662,7 +947,10 @@ public void Should_Return_False_If_Running_On_Bitrise() bitriseProvider.IsRunningOnBitrise.Returns(true); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -684,6 +972,9 @@ public void Should_Return_False_If_Running_On_TravisCI() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -694,7 +985,10 @@ public void Should_Return_False_If_Running_On_TravisCI() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(true); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -716,6 +1010,9 @@ public void Should_Return_False_If_Running_On_BitbucketPipelines() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -726,7 +1023,166 @@ public void Should_Return_False_If_Running_On_BitbucketPipelines() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(true); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsLocalBuild; + + // Then + Assert.False(result); + } + + [Fact] + public void Should_Return_False_If_Running_On_GoCD() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + appVeyorProvider.IsRunningOnAppVeyor.Returns(false); + teamCityProvider.IsRunningOnTeamCity.Returns(false); + myGetProvider.IsRunningOnMyGet.Returns(false); + bambooProvider.IsRunningOnBamboo.Returns(false); + continuaCIProvider.IsRunningOnContinuaCI.Returns(false); + jenkinsProvider.IsRunningOnJenkins.Returns(false); + bitriseProvider.IsRunningOnBitrise.Returns(false); + travisCIProvider.IsRunningOnTravisCI.Returns(false); + bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); + goCDProvider.IsRunningOnGoCD.Returns(true); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsLocalBuild; + + // Then + Assert.False(result); + } + + [Fact] + public void Should_Return_False_If_Running_On_GitLabCI() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + appVeyorProvider.IsRunningOnAppVeyor.Returns(false); + teamCityProvider.IsRunningOnTeamCity.Returns(false); + myGetProvider.IsRunningOnMyGet.Returns(false); + bambooProvider.IsRunningOnBamboo.Returns(false); + continuaCIProvider.IsRunningOnContinuaCI.Returns(false); + jenkinsProvider.IsRunningOnJenkins.Returns(false); + bitriseProvider.IsRunningOnBitrise.Returns(false); + travisCIProvider.IsRunningOnTravisCI.Returns(false); + bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); + goCDProvider.IsRunningOnGoCD.Returns(false); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(true); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsLocalBuild; + + // Then + Assert.False(result); + } + + [Fact] + public void Should_Return_False_If_Running_On_VSTS() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + appVeyorProvider.IsRunningOnAppVeyor.Returns(false); + teamCityProvider.IsRunningOnTeamCity.Returns(false); + myGetProvider.IsRunningOnMyGet.Returns(false); + bambooProvider.IsRunningOnBamboo.Returns(false); + continuaCIProvider.IsRunningOnContinuaCI.Returns(false); + jenkinsProvider.IsRunningOnJenkins.Returns(false); + bitriseProvider.IsRunningOnBitrise.Returns(false); + travisCIProvider.IsRunningOnTravisCI.Returns(false); + bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); + goCDProvider.IsRunningOnGoCD.Returns(false); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(true); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); + + // When + var result = buildSystem.IsLocalBuild; + + // Then + Assert.False(result); + } + + [Fact] + public void Should_Return_False_If_Running_On_TFS() + { + // Given + var appVeyorProvider = Substitute.For(); + var teamCityProvider = Substitute.For(); + var myGetProvider = Substitute.For(); + var bambooProvider = Substitute.For(); + var continuaCIProvider = Substitute.For(); + var jenkinsProvider = Substitute.For(); + var bitriseProvider = Substitute.For(); + var travisCIProvider = Substitute.For(); + var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); + + appVeyorProvider.IsRunningOnAppVeyor.Returns(false); + teamCityProvider.IsRunningOnTeamCity.Returns(false); + myGetProvider.IsRunningOnMyGet.Returns(false); + bambooProvider.IsRunningOnBamboo.Returns(false); + continuaCIProvider.IsRunningOnContinuaCI.Returns(false); + jenkinsProvider.IsRunningOnJenkins.Returns(false); + bitriseProvider.IsRunningOnBitrise.Returns(false); + travisCIProvider.IsRunningOnTravisCI.Returns(false); + bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); + goCDProvider.IsRunningOnGoCD.Returns(false); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(true); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; @@ -748,6 +1204,9 @@ public void Should_Return_True_If_Not_Running_On_Any() var bitriseProvider = Substitute.For(); var travisCIProvider = Substitute.For(); var bitbucketPipelinesProvider = Substitute.For(); + var goCDProvider = Substitute.For(); + var gitlabCIProvider = Substitute.For(); + var tfBuildProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(false); teamCityProvider.IsRunningOnTeamCity.Returns(false); @@ -757,7 +1216,11 @@ public void Should_Return_True_If_Not_Running_On_Any() bitriseProvider.IsRunningOnBitrise.Returns(false); travisCIProvider.IsRunningOnTravisCI.Returns(false); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(false); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + goCDProvider.IsRunningOnGoCD.Returns(false); + gitlabCIProvider.IsRunningOnGitLabCI.Returns(false); + tfBuildProvider.IsRunningOnVSTS.Returns(false); + tfBuildProvider.IsRunningOnTFS.Returns(false); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); // When var result = buildSystem.IsLocalBuild; diff --git a/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIBuildInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIBuildInfoTests.cs new file mode 100644 index 0000000000..4fad88b5cf --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIBuildInfoTests.cs @@ -0,0 +1,221 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GitLabCI.Data +{ + public sealed class GitLabCIBuildInfoTests + { + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal(50, result); + } + } + + public sealed class TheManualProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Manual; + + // Then + Assert.Equal(true, result); + } + } + + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("spec:other", result); + } + } + + public sealed class ThePipelineIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.PipelineId; + + // Then + Assert.Equal(1000, result); + } + } + + public sealed class TheReferenceProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Reference; + + // Then + Assert.Equal("1ecfd275763eff1d6b4844ea3168962458c9f27a", result); + } + } + + public sealed class TheRefNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.RefName; + + // Then + Assert.Equal("master", result); + } + } + + public sealed class TheRepoUrlProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.RepoUrl; + + // Then + Assert.Equal("https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/gitlab-org/gitlab-ce.git", result); + } + } + + public sealed class TheStageProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Stage; + + // Then + Assert.Equal("test", result); + } + } + + public sealed class TheTagProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Tag; + + // Then + Assert.Equal("1.0.0", result); + } + } + + public sealed class TheTokenProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Token; + + // Then + Assert.Equal("abcde-1234ABCD5678ef", result); + } + } + + public sealed class TheTriggeredProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.Triggered; + + // Then + Assert.Equal(true, result); + } + } + + public sealed class TheUserEmailProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.UserEmail; + + // Then + Assert.Equal("anthony@warwickcontrol.com", result); + } + } + + public sealed class TheUserIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateBuildInfo(); + + // When + var result = info.UserId; + + // Then + Assert.Equal(42, result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIProjectInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIProjectInfoTests.cs new file mode 100644 index 0000000000..3f29513e0d --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIProjectInfoTests.cs @@ -0,0 +1,109 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GitLabCI.Data +{ + public sealed class GitLabCIProjectInfoTests + { + public sealed class TheDirectoryProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateProjectInfo(); + + // When + var result = info.Directory; + + // Then + Assert.Equal("/builds/gitlab-org/gitlab-ce", result); + } + } + + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateProjectInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal(34, result); + } + } + + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateProjectInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("gitlab-ce", result); + } + } + + public sealed class TheNamespaceProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateProjectInfo(); + + // When + var result = info.Namespace; + + // Then + Assert.Equal("gitlab-org", result); + } + } + + public sealed class ThePathProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateProjectInfo(); + + // When + var result = info.Path; + + // Then + Assert.Equal("gitlab-org/gitlab-ce", result); + } + } + + public sealed class TheUrlProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateProjectInfo(); + + // When + var result = info.Url; + + // Then + Assert.Equal("https://gitlab.com/gitlab-org/gitlab-ce", result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIRunnerInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIRunnerInfoTests.cs new file mode 100644 index 0000000000..4225d2c6fe --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIRunnerInfoTests.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GitLabCI.Data +{ + public sealed class GitLabCIRunnerInfoTests + { + public sealed class TheDescriptionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateRunnerInfo(); + + // When + var result = info.Description; + + // Then + Assert.Equal("my runner", result); + } + } + + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateRunnerInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal(10, result); + } + } + + public sealed class TheTagsProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateRunnerInfo(); + + // When + var result = info.Tags; + + // Then + Assert.Equal(new[] { "docker", "linux" }, result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIServerInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIServerInfoTests.cs new file mode 100644 index 0000000000..67e373081d --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GitLabCI/Data/GitLabCIServerInfoTests.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GitLabCI.Data +{ + public sealed class GitLabCIServerInfoTests + { + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateServerInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("GitLab", result); + } + } + } + + public sealed class TheRevisionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateServerInfo(); + + // When + var result = info.Revision; + + // Then + Assert.Equal("70606bf", result); + } + } + + public sealed class TheVersionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GitLabCIInfoFixture().CreateServerInfo(); + + // When + var result = info.Version; + + // Then + Assert.Equal("8.9.0", result); + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/GitLabCI/GitLabCIProviderTests.cs b/src/Cake.Common.Tests/Unit/Build/GitLabCI/GitLabCIProviderTests.cs new file mode 100644 index 0000000000..0afbfb35bc --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GitLabCI/GitLabCIProviderTests.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GitLabCI +{ + public sealed class GitLabCIProviderTests + { + public sealed class TheConstructor + { + [Fact] + public void Should_Throw_If_Environment_Is_Null() + { + // Given, When + var result = Record.Exception(() => new GitLabCIProvider(null)); + + // Then + Assert.IsArgumentNullException(result, "environment"); + } + } + + public sealed class TheIsRunningOnGitLabCIProperty + { + [Fact] + public void Should_Return_True_If_Running_On_GitLabCI() + { + // Given + var fixture = new GitLabCIFixture(); + fixture.IsRunningOnGitLabCI(); + var gitlabCI = fixture.CreateGitLabCIService(); + + // When + var result = gitlabCI.IsRunningOnGitLabCI; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_If_Not_Running_On_GitLabCI() + { + // Given + var fixture = new GitLabCIFixture(); + var gitlabCI = fixture.CreateGitLabCIService(); + + // When + var result = gitlabCI.IsRunningOnGitLabCI; + + // Then + Assert.False(result); + } + } + + public sealed class TheEnvironmentProperty + { + [Fact] + public void Should_Return_Non_Null_Reference() + { + // Given + var fixture = new GitLabCIFixture(); + var gitlabCI = fixture.CreateGitLabCIService(); + + // When + var result = gitlabCI.Environment; + + // Then + Assert.NotNull(result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDEnvironmentInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDEnvironmentInfoTests.cs new file mode 100644 index 0000000000..b45ab71d37 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDEnvironmentInfoTests.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GoCD.Data +{ + public sealed class GoCDEnvironmentInfoTests + { + public sealed class TheGoCDUrlProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateEnvironmentInfo(); + + // When + var result = info.GoCDUrl; + + // Then + Assert.Equal("https://127.0.0.1:8154/go", result); + } + } + + public sealed class TheEnvironmentNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateEnvironmentInfo(); + + // When + var result = info.EnvironmentName; + + // Then + Assert.Equal("Development", result); + } + } + + public sealed class TheJobNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateEnvironmentInfo(); + + // When + var result = info.JobName; + + // Then + Assert.Equal("linux-firefox", result); + } + } + + public sealed class TheUserProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateEnvironmentInfo(); + + // When + var result = info.User; + + // Then + Assert.Equal("changes", result); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDPipelineInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDPipelineInfoTests.cs new file mode 100644 index 0000000000..32450ed105 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDPipelineInfoTests.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GoCD.Data +{ + public sealed class GoCDPipelineInfoTests + { + public sealed class ThePipelineNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreatePipelineInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("main", result); + } + } + + public sealed class ThePipelineCounterProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreatePipelineInfo(); + + // When + var result = info.Counter; + + // Then + Assert.Equal(2345, result); + } + } + + public sealed class ThePipelineLabelProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreatePipelineInfo(); + + // When + var result = info.Label; + + // Then + Assert.Equal("1.1.2345", result); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDRepositoryInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDRepositoryInfoTests.cs new file mode 100644 index 0000000000..f1d222573f --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDRepositoryInfoTests.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GoCD.Data +{ + public sealed class GoCDRepositoryInfoTests + { + public sealed class TheRevisionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.Revision; + + // Then + Assert.Equal("123", result); + } + } + + public sealed class TheFromRevisionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.FromRevision; + + // Then + Assert.Equal("122", result); + } + } + + public sealed class TheToRevisionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.ToRevision; + + // Then + Assert.Equal("124", result); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDStageInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDStageInfoTests.cs new file mode 100644 index 0000000000..0ee367662b --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GoCD/Data/GoCDStageInfoTests.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GoCD.Data +{ + public sealed class GoCDStageInfoTests + { + public sealed class TheCounterProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateStageInfo(); + + // When + var result = info.Counter; + + // Then + Assert.Equal(1, result); + } + } + + public sealed class TheStageNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new GoCDInfoFixture().CreateStageInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("dev", result); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/GoCD/GoCDProviderTests.cs b/src/Cake.Common.Tests/Unit/Build/GoCD/GoCDProviderTests.cs new file mode 100644 index 0000000000..0de98520a0 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/GoCD/GoCDProviderTests.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GoCD; +using Cake.Common.Tests.Fixtures.Build; +using Cake.Core; +using Cake.Core.Diagnostics; +using NSubstitute; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.GoCD +{ + public sealed class GoCDProviderTests + { + public sealed class TheConstructor + { + [Fact] + public void Should_Throw_If_Environment_Is_Null() + { + // Given, When + var cakeLog = Substitute.For(); + var result = Record.Exception(() => new GoCDProvider(null, cakeLog)); + + // Then + Assert.IsArgumentNullException(result, "environment"); + } + + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given, When + var environment = Substitute.For(); + var result = Record.Exception(() => new GoCDProvider(environment, null)); + + // Then + Assert.IsArgumentNullException(result, "cakeLog"); + } + } + + public sealed class TheIsRunningOnGoCDProperty + { + [Fact] + public void Should_Return_True_If_Running_On_GoCD() + { + // Given + var fixture = new GoCDFixture(); + fixture.IsRunningOnGoCD(); + var gocd = fixture.CreateGoCDService(); + + // When + var result = gocd.IsRunningOnGoCD; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_If_Not_Running_On_GoCD() + { + // Given + var fixture = new GoCDFixture(); + var gocd = fixture.CreateGoCDService(); + + // When + var result = gocd.IsRunningOnGoCD; + + // Then + Assert.False(result); + } + } + + public sealed class TheEnvironmentProperty + { + [Fact] + public void Should_Return_Non_Null_Reference() + { + // Given + var fixture = new GoCDFixture(); + var gocd = fixture.CreateGoCDService(); + + // When + var result = gocd.Environment; + + // Then + Assert.NotNull(result); + } + } + + public sealed class TheGetHistoryMethod + { + [Fact] + public void Should_Throw_If_Username_Is_Null() + { + // Given + var fixture = new GoCDFixture(); + var appVeyor = fixture.CreateGoCDService(); + + // When + var result = Record.Exception(() => appVeyor.GetHistory(null, "password")); + + // Then + Assert.IsArgumentNullException(result, "username"); + } + + [Fact] + public void Should_Throw_If_Password_Is_Null() + { + // Given + var fixture = new GoCDFixture(); + var appVeyor = fixture.CreateGoCDService(); + + // When + var result = Record.Exception(() => appVeyor.GetHistory("username", null)); + + // Then + Assert.IsArgumentNullException(result, "password"); + } + + [Fact] + public void Should_Throw_If_Not_Running_On_GoCD() + { + // Given + var fixture = new GoCDFixture(); + var appVeyor = fixture.CreateGoCDService(); + + // When + var result = Record.Exception(() => appVeyor.GetHistory("username", "password")); + + // Then + Assert.IsExceptionWithMessage(result, + "The current build is not running on Go.CD."); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildAgentInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildAgentInfoTests.cs new file mode 100644 index 0000000000..f5035007d5 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildAgentInfoTests.cs @@ -0,0 +1,137 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.TFBuild.Data +{ + public sealed class TFBuildAgentInfoTests + { + public sealed class TheBuildDirectoryProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.BuildDirectory; + + // Then + Assert.Equal("c:/agent/_work/1", result.FullPath); + } + } + + public sealed class TheHomeDirectoryProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.HomeDirectory; + + // Then + Assert.Equal("c:/agent", result.FullPath); + } + } + + public sealed class TheWorkingDirectoryProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.WorkingDirectory; + + // Then + Assert.Equal("c:/agent/_work", result.FullPath); + } + } + + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal(71, result); + } + } + + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("Agent-1", result); + } + } + + public sealed class TheMachineNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.MachineName; + + // Then + Assert.Equal("BuildServer", result); + } + } + + public sealed class TheIsHostedProperty + { + [Fact] + public void Should_Return_True_On_Hosted_Agent() + { + // Given + var info = new TFBuildInfoFixture().CreateHostedAgentInfo(); + + // When + var result = info.IsHosted; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_On_Other_Agent() + { + // Given + var info = new TFBuildInfoFixture().CreateAgentInfo(); + + // When + var result = info.IsHosted; + + // Then + Assert.False(result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildDefinitionInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildDefinitionInfoTests.cs new file mode 100644 index 0000000000..6447ffeb12 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildDefinitionInfoTests.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.TFBuild.Data +{ + public sealed class TFBuildDefinitionInfoTests + { + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateDefinitionInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal(1855, result); + } + } + + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateDefinitionInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("Cake-CI", result); + } + } + + public sealed class TheVersionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateDefinitionInfo(); + + // When + var result = info.Version; + + // Then + Assert.Equal(47, result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildInfoTests.cs new file mode 100644 index 0000000000..ccebe2e62b --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildInfoTests.cs @@ -0,0 +1,110 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.TFBuild.Data +{ + public sealed class TFBuildInfoTests + { + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateBuildInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal(100234, result); + } + } + + public sealed class TheNumberProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateBuildInfo(); + + // When + var result = info.Number; + + // Then + Assert.Equal("Build-20160927.1", result); + } + } + + public sealed class TheUriProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateBuildInfo(); + + // When + var result = info.Uri; + + // Then + var uri = new Uri("vstfs:///Build/Build/1430"); + Assert.Equal(uri, result); + } + } + + public sealed class TheQueuedByProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateBuildInfo(); + + // When + var result = info.QueuedBy; + + // Then + Assert.Equal(@"[DefaultCollection]\Project Collection Service Accounts", result); + } + } + + public sealed class TheRequestedForProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateBuildInfo(); + + // When + var result = info.RequestedFor; + + // Then + Assert.Equal("Alistair Chapman", result); + } + } + + public sealed class TheRequestedForEmailProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateBuildInfo(); + + // When + var result = info.RequestedForEmail; + + // Then + Assert.Equal("author@mail.com", result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildRepositoryInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildRepositoryInfoTests.cs new file mode 100644 index 0000000000..57977a7f59 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildRepositoryInfoTests.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.TFBuild.Data; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.TFBuild.Data +{ + public sealed class TFBuildRepositoryInfoTests + { + public sealed class TheBranchProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.Branch; + + // Then + Assert.Equal("develop", result); + } + } + + public sealed class TheSourceVersionProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.SourceVersion; + + // Then + Assert.Equal("4efbc1ffb993dfbcf024e6a9202865cc0b6d9c50", result); + } + } + + public sealed class TheShelvesetProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.Shelveset; + + // Then + Assert.Equal("Shelveset1", result); + } + } + + public sealed class TheRepoNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateRepositoryInfo(); + + // When + var result = info.RepoName; + + // Then + Assert.Equal("cake", result); + } + } + + public sealed class TheProviderProperty + { + [Theory] + [InlineData("Git", TFRepositoryType.Git)] + [InlineData("GitHub", TFRepositoryType.GitHub)] + [InlineData("Svn", TFRepositoryType.Svn)] + [InlineData("TfsGit", TFRepositoryType.TfsGit)] + [InlineData("TfsVersionControl", TFRepositoryType.TfsVersionControl)] + public void Should_Return_Correct_Value(string type, TFRepositoryType provider) + { + // Given + var info = new TFBuildInfoFixture().CreateRepositoryInfo(type); + + // When + var result = info.Provider; + + // Then + Assert.Equal(provider, result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildTeamProjectInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildTeamProjectInfoTests.cs new file mode 100644 index 0000000000..d66c617c1f --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/TFBuild/Data/TFBuildTeamProjectInfoTests.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.TFBuild.Data +{ + public sealed class TFBuildTeamProjectInfoTests + { + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateTeamProjectInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("TeamProject", result); + } + } + + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateTeamProjectInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal("D0A3B6B8-499B-4D4B-BD46-DB70C19E6D33", result); + } + } + + public sealed class TheCollectionUriProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new TFBuildInfoFixture().CreateTeamProjectInfo(); + + // When + var result = info.CollectionUri; + + // Then + var uri = new Uri("https://fabrikamfiber.visualstudio.com/"); + Assert.Equal(uri, result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/TFBuild/TFBuildProviderTests.cs b/src/Cake.Common.Tests/Unit/Build/TFBuild/TFBuildProviderTests.cs new file mode 100644 index 0000000000..720e02c889 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/TFBuild/TFBuildProviderTests.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.TFBuild; +using Cake.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.TFBuild +{ + public sealed class TFBuildProviderTests + { + public sealed class TheConstructor + { + [Fact] + public void Should_Throw_If_Environment_Is_Null() + { + // Given, When + var result = Record.Exception(() => new TFBuildProvider(null)); + + // Then + Assert.IsArgumentNullException(result, "environment"); + } + } + + public sealed class TheIsRunningOnVSTSProperty + { + [Fact] + public void Should_Return_True_If_Running_On_VSTS() + { + // Given + var fixture = new TFBuildFixture(); + fixture.IsRunningOnVSTS(); + var vsts = fixture.CreateTFBuildService(); + + // When + var result = vsts.IsRunningOnVSTS; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_If_Not_Running_On_VSTS() + { + // Given + var fixture = new TFBuildFixture(); + var vsts = fixture.CreateTFBuildService(); + + // When + var result = vsts.IsRunningOnVSTS; + + // Then + Assert.False(result); + } + } + + public sealed class TheIsRunningOnTFSProperty + { + [Fact] + public void Should_Return_True_If_Running_On_TFS() + { + // Given + var fixture = new TFBuildFixture(); + fixture.IsRunningOnTFS(); + var vsts = fixture.CreateTFBuildService(); + + // When + var result = vsts.IsRunningOnTFS; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_If_Not_Running_On_TFS() + { + // Given + var fixture = new TFBuildFixture(); + var vsts = fixture.CreateTFBuildService(); + + // When + var result = vsts.IsRunningOnTFS; + + // Then + Assert.False(result); + } + } + + public sealed class TheEnvironmentProperty + { + [Fact] + public void Should_Return_Non_Null_Reference() + { + // Given + var fixture = new TFBuildFixture(); + var vsts = fixture.CreateTFBuildService(); + + // When + var result = vsts.Environment; + + // Then + Assert.NotNull(result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/IO/DirectoryAliasesTests.cs b/src/Cake.Common.Tests/Unit/IO/DirectoryAliasesTests.cs index 46a853360c..151072e025 100644 --- a/src/Cake.Common.Tests/Unit/IO/DirectoryAliasesTests.cs +++ b/src/Cake.Common.Tests/Unit/IO/DirectoryAliasesTests.cs @@ -638,7 +638,7 @@ public void Should_Throw_If_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Temp/DoNotExist' do not exist.", result?.Message); + Assert.Equal("The directory '/Temp/DoNotExist' does not exist.", result?.Message); } [Fact] @@ -751,7 +751,7 @@ public void Should_Throw_If_Any_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Temp/DoNotExist' do not exist.", result?.Message); + Assert.Equal("The directory '/Temp/DoNotExist' does not exist.", result?.Message); } [Fact] @@ -875,7 +875,7 @@ public void Should_Throw_If_Any_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Temp/DoNotExist' do not exist.", result?.Message); + Assert.Equal("The directory '/Temp/DoNotExist' does not exist.", result?.Message); } [Fact] @@ -1207,5 +1207,102 @@ public void Should_Return_Absolute_Directory_Path() Assert.Equal("/Working/build", result.FullPath); } } + + public sealed class TheMoveDirectoryMethod + { + [Fact] + public void Should_Throw_If_Context_Is_Null() + { + // Given, When + var source = new DirectoryPath("./source"); + var target = new DirectoryPath("./target"); + + var result = Record.Exception(() => + DirectoryAliases.MoveDirectory(null, source, target)); + + // Then + Assert.IsArgumentNullException(result, "context"); + } + + [Fact] + public void Should_Throw_If_Source_Directory_Path_Is_Null() + { + // Given + var context = Substitute.For(); + var target = new DirectoryPath("./target"); + + // When + var result = Record.Exception(() => + DirectoryAliases.MoveDirectory(context, null, target)); + + // Then + Assert.IsArgumentNullException(result, "directoryPath"); + } + + [Fact] + public void Should_Throw_If_Target_Directory_Path_Is_Null() + { + // Given + var context = Substitute.For(); + var source = new DirectoryPath("./source"); + + // When + var result = Record.Exception(() => + DirectoryAliases.MoveDirectory(context, source, null)); + + // Then + Assert.IsArgumentNullException(result, "targetDirectoryPath"); + } + + [Fact] + public void Should_Recursively_Move_Files_And_Directory() + { + // Given + var context = Substitute.For(); + var environment = FakeEnvironment.CreateUnixEnvironment(); + var fileSystem = new FakeFileSystem(environment); + CreateFileStructure(fileSystem); + context.FileSystem.Returns(fileSystem); + var sourcePath = new DirectoryPath("/Temp"); + var destinationPath = new DirectoryPath("/Temp2"); + + // When + DirectoryAliases.MoveDirectory(context, sourcePath, destinationPath); + + // Then + Assert.False(fileSystem.GetDirectory("/Temp/Stuff").Exists); + Assert.False(fileSystem.GetDirectory("/Temp/Things").Exists); + Assert.True(fileSystem.GetDirectory("/Temp2/Stuff").Exists); + Assert.True(fileSystem.GetDirectory("/Temp2/Things").Exists); + + Assert.False(fileSystem.GetFile("/Temp/Stuff/file1.txt").Exists); + Assert.False(fileSystem.GetFile("/Temp/Stuff/file2.txt").Exists); + Assert.False(fileSystem.GetFile("/Temp/Things/file1.txt").Exists); + Assert.True(fileSystem.GetFile("/Temp2/Stuff/file1.txt").Exists); + Assert.True(fileSystem.GetFile("/Temp2/Stuff/file2.txt").Exists); + Assert.True(fileSystem.GetFile("/Temp2/Things/file1.txt").Exists); + } + + private static void CreateFileStructure(FakeFileSystem ffs) + { + Action dir = path => ffs.CreateDirectory(path); + Action file = path => ffs.CreateFile(path); + + dir("/Temp"); + { + file("/Temp/file1.txt"); + file("/Temp/file2.txt"); + dir("/Temp/Stuff"); + { + file("/Temp/Stuff/file1.txt"); + file("/Temp/Stuff/file2.txt"); + } + dir("/Temp/Things"); + { + file("/Temp/Things/file1.txt"); + } + } + } + } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/IO/FileAliasesTests.cs b/src/Cake.Common.Tests/Unit/IO/FileAliasesTests.cs index 63b9fc407d..18b1e52440 100644 --- a/src/Cake.Common.Tests/Unit/IO/FileAliasesTests.cs +++ b/src/Cake.Common.Tests/Unit/IO/FileAliasesTests.cs @@ -173,7 +173,7 @@ public void Should_Throw_If_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -190,7 +190,7 @@ public void Should_Throw_If_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file1.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file1.txt' does not exist.", result?.Message); } [Fact] @@ -284,7 +284,7 @@ public void Should_Throw_If_Any_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -301,7 +301,21 @@ public void Should_Throw_If_Any_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file2.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message); + } + + [Fact] + public void Should_Keep_Folder_Structure() + { + // Given + var fixture = new FileCopyFixture(); + + // When + FileAliases.CopyFiles(fixture.Context, fixture.SourceFilePaths, "./target"); + + // Then + fixture.TargetFiles[0].Received(1).Copy(Arg.Any(), true); + fixture.TargetFiles[1].Received(1).Copy(Arg.Any(), true); } [Fact] @@ -380,7 +394,7 @@ public void Should_Throw_If_Any_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -398,7 +412,22 @@ public void Should_Throw_If_Any_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file2.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message); + } + + [Fact] + public void Should_Keep_Folder_Structure() + { + // Given + var fixture = new FileCopyFixture(); + var filePaths = fixture.SourceFilePaths.Select(x => x.FullPath); + + // When + FileAliases.CopyFiles(fixture.Context, filePaths, "./target"); + + // Then + fixture.TargetFiles[0].Received(1).Copy(Arg.Any(), true); + fixture.TargetFiles[1].Received(1).Copy(Arg.Any(), true); } [Fact] @@ -472,7 +501,7 @@ public void Should_Throw_If_Any_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -489,7 +518,21 @@ public void Should_Throw_If_Any_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file2.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message); + } + + [Fact] + public void Should_Keep_Folder_Structure() + { + // Given + var fixture = new FileCopyFixture(); + + // When + FileAliases.CopyFiles(fixture.Context, "*", "./target", true); + + // Then + fixture.TargetFiles[0].Received(1).Copy(Arg.Any(), true); + fixture.TargetFiles[1].Received(1).Copy(Arg.Any(), true); } [Fact] @@ -550,7 +593,7 @@ public void Should_Throw_If_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/file.txt' do not exist.", result?.Message); + Assert.Equal("The file '/file.txt' does not exist.", result?.Message); } [Fact] @@ -792,7 +835,7 @@ public void Should_Throw_If_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -809,7 +852,7 @@ public void Should_Throw_If_Any_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file2.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message); } [Fact] @@ -882,7 +925,7 @@ public void Should_Throw_If_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -899,7 +942,7 @@ public void Should_Throw_If_Any_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file2.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file2.txt' does not exist.", result?.Message); } [Fact] @@ -978,7 +1021,7 @@ public void Should_Throw_If_Target_Directory_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The directory '/Working/target' do not exist.", result?.Message); + Assert.Equal("The directory '/Working/target' does not exist.", result?.Message); } [Fact] @@ -995,7 +1038,7 @@ public void Should_Throw_If_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("The file '/Working/file1.txt' do not exist.", result?.Message); + Assert.Equal("The file '/Working/file1.txt' does not exist.", result?.Message); } [Fact] diff --git a/src/Cake.Common.Tests/Unit/ReleaseNotesAliasesTests.cs b/src/Cake.Common.Tests/Unit/ReleaseNotesAliasesTests.cs index cf08095c97..4a68dfb4b1 100644 --- a/src/Cake.Common.Tests/Unit/ReleaseNotesAliasesTests.cs +++ b/src/Cake.Common.Tests/Unit/ReleaseNotesAliasesTests.cs @@ -42,7 +42,7 @@ public void Should_Throw_If_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("Release notes file '/Working/ReleaseNotes.md' do not exist.", result?.Message); + Assert.Equal("Release notes file '/Working/ReleaseNotes.md' does not exist.", result?.Message); } [Fact] diff --git a/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs index 7a3b619ba8..5b6eabd0d7 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs @@ -235,6 +235,23 @@ public void Should_Append_DisableDefaultFilters() "/DisableDefaultFilters", result.Args); } + [Fact] + public void Should_Append_LogFile() + { + // Given + var fixture = new DotCoverAnalyserFixture(); + fixture.Settings.LogFile = "./logfile.log"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("Analyse /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.xml\" " + + "/LogFile=\"/Working/logfile.log\"", result.Args); + } + [Fact] public void Should_Capture_XUnit() { diff --git a/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs new file mode 100644 index 0000000000..1bd196a166 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Tools.DotCover.Report; +using Cake.Common.Tools.DotCover; +using Cake.Common.Tools.NUnit; +using Cake.Common.Tools.XUnit; +using Cake.Core.IO; +using Cake.Testing; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.DotCover.Report +{ + public sealed class DotCoverReporterTests + { + public sealed class TheReportMethod + { + [Fact] + public void Should_Throw_If_Source_File_Is_Null() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.SourceFile = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "sourceFile"); + } + + [Fact] + public void Should_Throw_If_Output_File_Is_Null() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "outputFile"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.Settings = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "settings"); + } + + [Theory] + [InlineData(DotCoverReportType.DetailedXML, "DetailedXML")] + [InlineData(DotCoverReportType.HTML, "HTML")] + [InlineData(DotCoverReportType.JSON, "JSON")] + [InlineData(DotCoverReportType.NDependXML, "NDependXML")] + public void Should_Append_ReportType(DotCoverReportType reportType, string reportTypeString) + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.Settings.ReportType = reportType; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("Report " + + "/Source=\"/Working/result.dcvr\" " + + "/Output=\"/Working/result.xml\" " + + "/ReportType=" + reportTypeString, result.Args); + } + + [Fact] + public void Should_Append_LogFile() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.Settings.LogFile = "./logfile.log"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("Report " + + "/Source=\"/Working/result.dcvr\" " + + "/Output=\"/Working/result.xml\" " + + "/LogFile=\"/Working/logfile.log\"", result.Args); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/InnoSetup/InnoSetupAliasesTests.cs b/src/Cake.Common.Tests/Unit/Tools/InnoSetup/InnoSetupAliasesTests.cs new file mode 100644 index 0000000000..b6233c7c23 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/InnoSetup/InnoSetupAliasesTests.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.InnoSetup; +using Cake.Core; +using NSubstitute; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.InnoSetup +{ + public class InnoSetupAliasesTests + { + public sealed class TheInnoSetupMethod + { + [Fact] + public void Should_Throw_If_Context_Is_Null() + { + // Given, When + var result = Record.Exception(() => InnoSetupAliases.InnoSetup(null, "some file.iss")); + + // Then + Assert.IsArgumentNullException(result, "context"); + } + + [Fact] + public void Should_Throw_If_Script_Path_Is_Null() + { + // Given + var context = Substitute.For(); + + // When + var result = Record.Exception(() => InnoSetupAliases.InnoSetup(context, null)); + + // Then + Assert.IsArgumentNullException(result, "scriptFile"); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Tools/InnoSetup/InnoSetupRunnerTests.cs b/src/Cake.Common.Tests/Unit/Tools/InnoSetup/InnoSetupRunnerTests.cs new file mode 100644 index 0000000000..c435aa63e0 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/InnoSetup/InnoSetupRunnerTests.cs @@ -0,0 +1,284 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Cake.Common.Tests.Fixtures.Tools; +using Cake.Common.Tools.InnoSetup; +using Cake.Core; +using Cake.Testing; +using Cake.Testing.Xunit; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.InnoSetup +{ + public class InnoSetupRunnerTests + { + public sealed class TheRunMethod + { + [Fact] + public void Should_Throw_If_Script_File_Is_Null() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.ScriptPath = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "scriptFile"); + } + + [Fact] + public void Should_Throw_If_Settings_Is_Null() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "settings"); + } + + [Fact] + public void Should_Throw_If_InnoSetup_Runner_Was_Not_Found() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.GivenDefaultToolDoNotExist(); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsType(result); + Assert.Equal("InnoSetup: Could not locate executable.", result?.Message); + } + + [Theory] + [InlineData("/bin/inno/iscc.exe", "/bin/inno/iscc.exe")] + [InlineData("./tools/inno/iscc.exe", "/Working/tools/inno/iscc.exe")] + public void Should_Use_InnoSetup_Runner_From_Tool_Path_If_Provided(string toolPath, string expected) + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.ToolPath = toolPath; + fixture.GivenSettingsToolPathExist(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(expected, result.Path.FullPath); + } + + [WindowsTheory] + [InlineData("C:/inno/iscc.exe", "C:/inno/iscc.exe")] + public void Should_Use_InnoSetup_Runner_From_Tool_Path_If_Provided_On_Windows(string toolPath, string expected) + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.ToolPath = toolPath; + fixture.GivenSettingsToolPathExist(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(expected, result.Path.FullPath); + } + + [Fact] + public void Should_Find_InnoSetup_Runner_If_Tool_Path_Not_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/Working/tools/iscc.exe", result.Path.FullPath); + } + + [WindowsFact] + public void Should_Find_InnoSetup_Runner_In_Installation_Path_If_Tool_Path_Not_Provided_x86() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.GivenDefaultToolDoNotExist(); + fixture.GivenToolIsInstalledX86(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(fixture.InstalledToolPath.FullPath, result.Path.FullPath); + } + + [WindowsFact] + public void Should_Find_InnoSetup_Runner_In_Installation_Path_If_Tool_Path_Not_Provided_x64() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.GivenDefaultToolDoNotExist(); + fixture.GivenToolIsInstalledX64(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(fixture.InstalledToolPath.FullPath, result.Path.FullPath); + } + + [Fact] + public void Should_Set_Working_Directory() + { + // Given + var fixture = new InnoSetupFixture(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/Working", result.Process.WorkingDirectory.FullPath); + } + + [Fact] + public void Should_Throw_If_Process_Was_Not_Started() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.GivenProcessCannotStart(); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsType(result); + Assert.Equal("InnoSetup: Process was not started.", result?.Message); + } + + [Fact] + public void Should_Throw_If_Process_Has_A_Non_Zero_Exit_Code() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.GivenProcessExitsWithCode(1); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsType(result); + Assert.Equal("InnoSetup: Process returned an error (exit code 1).", result?.Message); + } + + [Fact] + public void Should_Add_Defines_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.Defines = new Dictionary(); + fixture.Settings.Defines.Add("Foo", "Bar"); + fixture.Settings.Defines.Add("Test", null); + fixture.Settings.Defines.Add("Test2", string.Empty); + fixture.Settings.Defines.Add("Test3", "hello world"); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/DFoo=\"Bar\" /DTest /DTest2 /DTest3=\"hello world\" \"/Working/Test.iss\"", result.Args); + } + + [Fact] + public void Should_Add_OutputOn_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.EnableOutput = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/O+ \"/Working/Test.iss\"", result.Args); + } + + [Fact] + public void Should_Add_OutputOff_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.EnableOutput = false; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/O- \"/Working/Test.iss\"", result.Args); + } + + [Fact] + public void Should_Add_OutputDir_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.OutputDirectory = "SetupOutput"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/O\"/Working/SetupOutput\" \"/Working/Test.iss\"", result.Args); + } + + [Fact] + public void Should_Add_OutputBaseFilename_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.OutputBaseFilename = "Test-setup"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/F\"Test-setup\" \"/Working/Test.iss\"", result.Args); + } + + [Fact] + public void Should_Add_QuietMode_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.QuietMode = InnoSetupQuietMode.Quiet; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/Q \"/Working/Test.iss\"", result.Args); + } + + [Fact] + public void Should_Add_QuietModeWithProgress_To_Arguments_If_Provided() + { + // Given + var fixture = new InnoSetupFixture(); + fixture.Settings.QuietMode = InnoSetupQuietMode.QuietWithProgress; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/Qp \"/Working/Test.iss\"", result.Args); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildRunnerTests.cs b/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildRunnerTests.cs index 38147c1f21..ec58020ad6 100644 --- a/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildRunnerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildRunnerTests.cs @@ -583,6 +583,36 @@ public void Should_Use_Node_Reuse_If_Specified() "\"/Working/src/Solution.sln\"", result.Args); } + [Fact] + public void Should_Use_Detailed_Summary_If_Specified() + { + // Given + var fixture = new MSBuildRunnerFixture(false); + fixture.Settings.DetailedSummary = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/ds /v:normal /target:Build " + + "\"/Working/src/Solution.sln\"", result.Args); + } + + [Fact] + public void Should_Use_No_Console_Logger_If_Specified() + { + // Given + var fixture = new MSBuildRunnerFixture(false); + fixture.Settings.NoConsoleLogger = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("/noconlog /v:normal /target:Build " + + "\"/Working/src/Solution.sln\"", result.Args); + } + [Fact] public void Should_Append_Targets_To_Process_Arguments() { @@ -802,6 +832,63 @@ public void Should_Append_Logger_To_Process_Arguments() Assert.Equal("/v:normal /target:Build /logger:B,A;C /logger:E,D /logger:F " + "\"/Working/src/Solution.sln\"", result.Args); } + + [Fact] + public void Should_Append_FileLogger_To_Process_Arguments() + { + // Given + var fixture = new MSBuildRunnerFixture(false); + fixture.Settings.AddFileLogger(new MSBuildFileLogger { AppendToLogFile = false, Encoding = "E", HideVerboseItemAndPropertyList = false, LogFile = "A", MSBuildFileLoggerOutput = MSBuildFileLoggerOutput.All, PerformanceSummaryEnabled = false, ShowCommandLine = false, ShowEventId = false, ShowTimestamp = false, SummaryDisabled = false, Verbosity = Verbosity.Diagnostic }); + fixture.Settings.AddFileLogger(new MSBuildFileLogger { AppendToLogFile = true, HideVerboseItemAndPropertyList = true, MSBuildFileLoggerOutput = MSBuildFileLoggerOutput.ErrorsOnly, PerformanceSummaryEnabled = true, ShowCommandLine = true, ShowEventId = true, ShowTimestamp = true, SummaryDisabled = true, Verbosity = Verbosity.Minimal }); + fixture.Settings.AddFileLogger(new MSBuildFileLogger { MSBuildFileLoggerOutput = MSBuildFileLoggerOutput.WarningsOnly, Verbosity = Verbosity.Normal }); + fixture.Settings.AddFileLogger(new MSBuildFileLogger { Verbosity = Verbosity.Quiet }); + fixture.Settings.AddFileLogger(new MSBuildFileLogger { Verbosity = Verbosity.Verbose }); + fixture.Settings.AddFileLogger(new MSBuildFileLogger { }); + fixture.Settings.AddFileLogger(); + + // When + var result = fixture.Run(); + // Then + Assert.Equal(@"/v:normal /target:Build /fl /flp:logfile=A;Encoding=E;Verbosity=Diagnostic /fl1 /flp1:Append;PerformanceSummary;NoSummary;ErrorsOnly;NoItemAndPropertyList;ShowCommandLine;ShowTimestamp;ShowEventId;Verbosity=Minimal /fl2 /flp2:WarningsOnly;Verbosity=Normal /fl3 /flp3:Verbosity=Quiet /fl4 /flp4:Verbosity=Verbose /fl5 /fl6 ""/Working/src/Solution.sln""", result.Args); + } + + [Fact] + public void Should_Append_Default_FileLogger_To_Process_Arguments() + { + // Given + var fixture = new MSBuildRunnerFixture(false); + fixture.Settings.AddFileLogger(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(@"/v:normal /target:Build /fl ""/Working/src/Solution.sln""", result.Args); + } + + [Fact] + public void Should_Throw_Exception_For_Too_Many_FileLoggers() + { + // Given + var fixture = new MSBuildRunnerFixture(false); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + fixture.Settings.AddFileLogger(); + + // When + var ex = Assert.Throws(() => fixture.Run()); + + // Then + Assert.Equal(@"Too Many FileLoggers", ex.Message); + } } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsExtensionsTests.cs b/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsExtensionsTests.cs index 7a50a76c42..1b89ee9c1b 100644 --- a/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsExtensionsTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsExtensionsTests.cs @@ -229,6 +229,68 @@ public void Should_Return_The_Same_Configuration() } } + public sealed class TheDetailedSummaryMethod + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Set_Detailed_Summary(bool detailedSummary) + { + // Given + var settings = new MSBuildSettings(); + + // When + settings.SetDetailedSummary(detailedSummary); + + // Then + Assert.Equal(detailedSummary, settings.DetailedSummary); + } + + [Fact] + public void Should_Return_The_Same_Configuration() + { + // Given + var settings = new MSBuildSettings(); + + // When + var result = settings.SetDetailedSummary(true); + + // Then + Assert.Equal(settings, result); + } + } + + public sealed class TheNoConsoleLoggerMethod + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Set_No_Console_Logger(bool noConsoleLog) + { + // Given + var settings = new MSBuildSettings(); + + // When + settings.SetNoConsoleLogger(noConsoleLog); + + // Then + Assert.Equal(noConsoleLog, settings.NoConsoleLogger); + } + + [Fact] + public void Should_Return_The_Same_Configuration() + { + // Given + var settings = new MSBuildSettings(); + + // When + var result = settings.SetNoConsoleLogger(true); + + // Then + Assert.Equal(settings, result); + } + } + public sealed class TheSetVerbosityMethod { [Theory] @@ -299,5 +361,43 @@ public void Should_Return_The_Same_Configuration() Assert.Equal(settings, result); } } + + public sealed class TheAddFileLoggersMethod + { + [Fact] + public void Should_Add_Logger() + { + // Given + var settings = new MSBuildSettings(); + var fileLogger = new MSBuildFileLogger(); + var fileLogger2 = new MSBuildFileLogger { LogFile = "A" }; + + // When + settings.AddFileLogger(fileLogger); + settings.AddFileLogger(fileLogger2); + + // Then + var loggers = settings.FileLoggers.ToArray(); + Assert.Equal(2, loggers.Length); + Assert.Equal(fileLogger, loggers[0]); + Assert.Equal(fileLogger2, loggers[1]); + Assert.Equal("A", loggers[1].LogFile); + } + + [Fact] + public void Should_Return_The_Same_Configuration() + { + // Given + var settings = new MSBuildSettings(); + + // When + var result = settings.AddFileLogger(new MSBuildFileLogger()); + var result1 = settings.AddFileLogger(); + + // Then + Assert.Equal(settings, result); + Assert.Equal(settings, result1); + } + } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsTests.cs b/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsTests.cs index 869d71b1c7..632720b4e7 100644 --- a/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/MSBuild/MSBuildSettingsTests.cs @@ -114,6 +114,32 @@ public void Should_Be_Null_By_Default() } } + public sealed class TheDetailedSummaryProperty + { + [Fact] + public void Should_Be_Null_By_Default() + { + // Given + var settings = new MSBuildSettings(); + + // Then + Assert.Null(settings.DetailedSummary); + } + } + + public sealed class TheNoConsoleLogProperty + { + [Fact] + public void Should_Be_Null_By_Default() + { + // Given + var settings = new MSBuildSettings(); + + // Then + Assert.Null(settings.NoConsoleLogger); + } + } + public sealed class TheLoggersProperty { [Fact] @@ -126,5 +152,18 @@ public void Should_Be_Empty_By_Default() Assert.Empty(settings.Loggers); } } + + public sealed class TheFileLoggersProperty + { + [Fact] + public void Should_Be_Empty_By_Default() + { + // Given + var settings = new MSBuildSettings(); + + // Then + Assert.Empty(settings.FileLoggers); + } + } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/NuGet/Pack/NuGetPackerTests.cs b/src/Cake.Common.Tests/Unit/Tools/NuGet/Pack/NuGetPackerTests.cs index 412783fdc2..8b96d43d49 100644 --- a/src/Cake.Common.Tests/Unit/Tools/NuGet/Pack/NuGetPackerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/NuGet/Pack/NuGetPackerTests.cs @@ -481,6 +481,109 @@ public void Should_Add_MSBuildVersion_To_Arguments_If_Set(NuGetMSBuildVersion ms // Then Assert.Equal(expected, result.Args); } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Keep_NuSpec_File_According_To_Flag(bool keepTemporaryNuSpecFile) + { + // Given + var fixture = new NuGetPackerWithNuSpecFixture(); + fixture.Settings.KeepTemporaryNuSpecFile = keepTemporaryNuSpecFile; + + // When + fixture.Run(); + + // Then + Assert.Equal(keepTemporaryNuSpecFile, fixture.FileSystem.Exist((FilePath)"/Working/existing.temp.nuspec")); + } + + [Fact] + public void Should_Replace_Template_Tokens_In_Nuspec_With_Files_And_DependencyTargetFramework() + { + // Given + var fixture = new NuGetPackerWithNuSpecFixture(); + + fixture.Settings.Id = "The ID"; + fixture.Settings.Version = "The version"; + fixture.Settings.Title = "The title"; + fixture.Settings.Authors = new[] { "Author #1", "Author #2" }; + fixture.Settings.Owners = new[] { "Owner #1", "Owner #2" }; + fixture.Settings.Description = "The description"; + fixture.Settings.Summary = "The summary"; + fixture.Settings.LicenseUrl = new Uri("https://license.com"); + fixture.Settings.ProjectUrl = new Uri("https://project.com"); + fixture.Settings.IconUrl = new Uri("https://icon.com"); + fixture.Settings.DevelopmentDependency = true; + fixture.Settings.RequireLicenseAcceptance = true; + fixture.Settings.Copyright = "The copyright"; + fixture.Settings.ReleaseNotes = new[] { "Line #1", "Line #2", "Line #3" }; + fixture.Settings.Tags = new[] { "Tag1", "Tag2", "Tag3" }; + fixture.Settings.Files = new[] + { + new NuSpecContent { Source = "Cake.Core.dll", Target = "lib/net45" }, + new NuSpecContent { Source = "Cake.Core.xml", Target = "lib/net45" }, + new NuSpecContent { Source = "Cake.Core.pdb", Target = "lib/net45" }, + new NuSpecContent { Source = "LICENSE" } + }; + fixture.Settings.Dependencies = new[] + { + new NuSpecDependency { Id = "Test1", Version = "1.0.0", TargetFramework = "net452" }, + new NuSpecDependency { Id = "Test2", Version = "[1.0.0]", TargetFramework = "net462" } + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal( + Resources.Nuspec_Metadata_WithTragetFramworkDependencies.NormalizeLineEndings(), + result.NuspecContent.NormalizeLineEndings()); + } + + [Fact] + public void Should_Replace_Template_Tokens_In_Nuspec_With_Files_And_DependencyTargetFramework_Without_Namespaces() + { + // Given + var fixture = new NuGetPackerWithNuSpecFixture(); + fixture.WithNuSpecXml(Resources.Nuspec_NoMetadataValues_WithoutNamespaces); + + fixture.Settings.Id = "The ID"; + fixture.Settings.Version = "The version"; + fixture.Settings.Title = "The title"; + fixture.Settings.Authors = new[] { "Author #1", "Author #2" }; + fixture.Settings.Owners = new[] { "Owner #1", "Owner #2" }; + fixture.Settings.Description = "The description"; + fixture.Settings.Summary = "The summary"; + fixture.Settings.LicenseUrl = new Uri("https://license.com"); + fixture.Settings.ProjectUrl = new Uri("https://project.com"); + fixture.Settings.IconUrl = new Uri("https://icon.com"); + fixture.Settings.DevelopmentDependency = true; + fixture.Settings.RequireLicenseAcceptance = true; + fixture.Settings.Copyright = "The copyright"; + fixture.Settings.ReleaseNotes = new[] { "Line #1", "Line #2", "Line #3" }; + fixture.Settings.Tags = new[] { "Tag1", "Tag2", "Tag3" }; + fixture.Settings.Files = new[] + { + new NuSpecContent { Source = "Cake.Core.dll", Target = "lib/net45" }, + new NuSpecContent { Source = "Cake.Core.xml", Target = "lib/net45" }, + new NuSpecContent { Source = "Cake.Core.pdb", Target = "lib/net45" }, + new NuSpecContent { Source = "LICENSE" } + }; + fixture.Settings.Dependencies = new[] + { + new NuSpecDependency { Id = "Test1", Version = "1.0.0", TargetFramework = "net452" }, + new NuSpecDependency { Id = "Test2", Version = "[1.0.0]", TargetFramework = "net462" } + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal( + Resources.Nuspec_Metadata_WithoutNamespaces_WithTargetFramworkDependencies.NormalizeLineEndings(), + result.NuspecContent.NormalizeLineEndings()); + } } public sealed class WithProjectFile @@ -837,6 +940,30 @@ public void Should_Pack_If_Sufficient_Settings_Specified() "\"/Working/nonexisting.temp.nuspec\"", result.Args); } + [Fact] + public void Should_Pack_If_Sufficient_Settings_For_MetaPackage_Specified() + { + // Given + var fixture = new NuGetPackerWithoutNuSpecFixture(); + fixture.Settings.OutputDirectory = "/Working/"; + fixture.Settings.Id = "nonexisting"; + fixture.Settings.Version = "1.0.0"; + fixture.Settings.Description = "The description"; + fixture.Settings.Authors = new[] { "Author #1", "Author #2" }; + fixture.Settings.Files = null; + fixture.Settings.Dependencies = new List + { + new NuSpecDependency { Id = "Test1", Version = "1.0.0" } + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack -Version \"1.0.0\" -OutputDirectory \"/Working\" " + + "\"/Working/nonexisting.temp.nuspec\"", result.Args); + } + [Fact] public void Should_Throw_If_OutputDirectory_Setting_Not_Specified() { @@ -913,7 +1040,7 @@ public void Should_Throw_If_Description_Setting_Not_Specified() } [Fact] - public void Should_Throw_If_Files_Setting_Not_Specified() + public void Should_Throw_If_Files_Setting_And_Dependencies_Not_Specified() { // Given var fixture = new NuGetPackerWithoutNuSpecFixture(); @@ -922,13 +1049,40 @@ public void Should_Throw_If_Files_Setting_Not_Specified() fixture.Settings.Version = "1.0.0"; fixture.Settings.Authors = new[] { "Author #1", "Author #2" }; fixture.Settings.Description = "The description"; - + fixture.Settings.Dependencies = null; + fixture.Settings.Files = null; // When var result = Record.Exception(() => fixture.Run()); // Then Assert.IsCakeException(result, "Required setting Files not specified."); } + + [Fact] + public void Should_Pack_If_Sufficient_Settings_For_MetaPackage_With_TargetFrameWork_Specified() + { + // Given + var fixture = new NuGetPackerWithoutNuSpecFixture(); + fixture.Settings.OutputDirectory = "/Working/"; + fixture.Settings.Id = "nonexisting"; + fixture.Settings.Version = "1.0.0"; + fixture.Settings.Description = "The description"; + fixture.Settings.Authors = new[] { "Author #1", "Author #2" }; + fixture.Settings.Files = null; + fixture.Settings.Dependencies = new List + { + new NuSpecDependency { Id = "Test1", Version = "1.0.0", TargetFramework = "net452" }, + new NuSpecDependency { Id = "Test1", Version = "1.0.0", TargetFramework = "net462" } + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal( + Resources.Nuspec_Metadata_WithTargetFrameworkDependencies.NormalizeLineEndings(), + result.NuspecContent.NormalizeLineEndings()); + } } } } diff --git a/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoCreateReleaseTests.cs b/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoCreateReleaseTests.cs index bb85225dd6..bebf847ba3 100644 --- a/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoCreateReleaseTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoCreateReleaseTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using Cake.Common.Tests.Fixtures.Tools; using Cake.Testing; @@ -189,7 +190,7 @@ public void Should_Add_Username_To_Arguments_If_Not_Null() // Then Assert.Equal("create-release --project \"testProject\" " + "--server http://octopus --apiKey API-12345 " + - "--username \"mike123\"", result.Args); + "--user \"mike123\"", result.Args); } [Fact] @@ -205,7 +206,7 @@ public void Should_Add_Password_To_Arguments_If_Not_Null() // Then Assert.Equal("create-release --project \"testProject\" " + "--server http://octopus --apiKey API-12345 " + - "--password \"secret\"", result.Args); + "--pass \"secret\"", result.Args); } [Fact] @@ -393,7 +394,7 @@ public void Should_Add_Release_Notes_File_To_Arguments_If_Not_Null() } [Fact] - public void Should_Add_Ignore_Existing_Flag_To_Arguments_If_Not_Null() + public void Should_Add_Ignore_Existing_Flag_To_Arguments_If_True() { // Given var fixture = new OctopusDeployReleaseCreatorFixture(); @@ -407,6 +408,453 @@ public void Should_Add_Ignore_Existing_Flag_To_Arguments_If_Not_Null() "--server http://octopus --apiKey API-12345 " + "--ignoreexisting", result.Args); } + } + + public sealed class DeploymentAgrumentsBuilder + { + [Fact] + public void Should_Add_DeployTo_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\"", result.Args); + } + + [Fact] + public void Should_Add_Progress_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.ShowProgress = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--progress", result.Args); + } + + [Fact] + public void Should_Add_FocePackageDownload_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.ForcePackageDownload = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--forcepackagedownload", result.Args); + } + + [Fact] + public void Should_Add_WaitForDeployment_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.WaitForDeployment = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--waitfordeployment", result.Args); + } + + [Fact] + public void Should_Add_DeploymentTimeout_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.DeploymentTimeout = TimeSpan.FromMinutes(1); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--deploymenttimeout=\"00:01:00\"", result.Args); + } + + [Fact] + public void Should_Add_CancelTimeout_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.CancelOnTimeout = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--cancelontimeout", result.Args); + } + + [Fact] + public void Should_Add_DeploymentChecksLeepCycle_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.DeploymentChecksLeepCycle = TimeSpan.FromMinutes(77); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--deploymentchecksleepcycle=\"01:17:00\"", result.Args); + } + + [Fact] + public void Should_Add_GuidedFailure_To_Arguments_If_True() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.GuidedFailure = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--guidedfailure=True", result.Args); + } + + [Fact] + public void Should_Add_GuidedFailure_To_Arguments_If_False() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.GuidedFailure = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--guidedfailure=True", result.Args); + } + + [Fact] + public void Should_Add_SpecificMachines_To_Arguments_If_NotNull() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.SpecificMachines = new string[] { "Machine1", "Machine2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--specificmachines=\"Machine1,Machine2\"", result.Args); + } + + [Fact] + public void Should_Add_Force_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.Force = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--force", result.Args); + } + + [Fact] + public void Should_Add_SkipSteps_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.SkipSteps = new[] { "Step1", "Step2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--skip=\"Step1\" " + + "--skip=\"Step2\"", result.Args); + } + + [Fact] + public void Should_Add_NoRawLog_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.NoRawLog = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--norawlog", result.Args); + } + + [Fact] + public void Should_Add_RawLogFile_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.RawLogFile = "someFile.txt"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--rawlogfile \"/Working/someFile.txt\"", result.Args); + } + + [Fact] + public void Should_Add_Variables_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.Variables.Add(new KeyValuePair("var1", "value1")); + fixture.Settings.Variables.Add(new KeyValuePair("var2", "value2")); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--variable=\"var1:value1\" " + + "--variable=\"var2:value2\"", result.Args); + } + + [Fact] + public void Should_Add_DeployAt_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.DeployAt = new DateTime(2010, 6, 15).AddMinutes(1); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--deployat=\"2010-06-15 00:01\"", result.Args); + } + + [Fact] + public void Should_Add_Tenants_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.Tenant = new[] { "Tenant1", "Tenant2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--tenant=\"Tenant1\" " + + "--tenant=\"Tenant2\"", result.Args); + } + + [Fact] + public void Should_Add_TenantTags_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.TenantTags = new[] { "Tag1", "Tag2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--tenanttag=\"Tag1\" " + + "--tenanttag=\"Tag2\"", result.Args); + } + + [Fact] + public void Should_Add_All_Deploymnet_Arguments() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = "SomeEnvironment"; + fixture.Settings.ShowProgress = true; + fixture.Settings.ForcePackageDownload = true; + fixture.Settings.WaitForDeployment = true; + fixture.Settings.DeploymentTimeout = TimeSpan.FromMinutes(1); + fixture.Settings.CancelOnTimeout = true; + fixture.Settings.DeploymentChecksLeepCycle = TimeSpan.FromMinutes(77); + fixture.Settings.GuidedFailure = true; + fixture.Settings.SpecificMachines = new string[] { "Machine1", "Machine2" }; + fixture.Settings.Force = true; + fixture.Settings.SkipSteps = new[] { "Step1", "Step2" }; + fixture.Settings.NoRawLog = true; + fixture.Settings.RawLogFile = "someFile.txt"; + fixture.Settings.Variables.Add(new KeyValuePair("var1", "value1")); + fixture.Settings.Variables.Add(new KeyValuePair("var2", "value2")); + fixture.Settings.DeployAt = new DateTime(2010, 6, 15).AddMinutes(1); + fixture.Settings.Tenant = new[] { "Tenant1", "Tenant2" }; + fixture.Settings.TenantTags = new[] { "Tag1", "Tag2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"SomeEnvironment\" " + + "--progress " + + "--forcepackagedownload " + + "--waitfordeployment " + + "--deploymenttimeout=\"00:01:00\" " + + "--cancelontimeout " + + "--deploymentchecksleepcycle=\"01:17:00\" " + + "--guidedfailure=True " + + "--specificmachines=\"Machine1,Machine2\" " + + "--force " + + "--skip=\"Step1\" " + + "--skip=\"Step2\" " + + "--norawlog " + + "--rawlogfile \"/Working/someFile.txt\" " + + "--variable=\"var1:value1\" " + + "--variable=\"var2:value2\" " + + "--deployat=\"2010-06-15 00:01\" " + + "--tenant=\"Tenant1\" " + + "--tenant=\"Tenant2\" " + + "--tenanttag=\"Tag1\" " + + "--tenanttag=\"Tag2\"", result.Args); + } + + [Fact] + public void Should_Add_Channel_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.Channel = @"somechannel"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--channel \"somechannel\"", result.Args); + } + + [Fact] + public void Should_Add_Ignore_Channel_Rules_To_Arguments_If_True() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.IgnoreChannelRules = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--ignorechannelrules", result.Args); + } + + [Fact] + public void Should_Add_Deployment_Environment_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeployTo = @"someenvironment"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--deployto \"someenvironment\"", result.Args); + } + + [Fact] + public void Should_Add_Deployment_Progress_To_Arguments_If_True() + { + // Given + var fixture = new OctopusDeployReleaseCreatorFixture(); + fixture.Settings.DeploymentProgress = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("create-release --project \"testProject\" " + + "--server http://octopus --apiKey API-12345 " + + "--progress", result.Args); + } } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoDeployReleaseTests.cs b/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoDeployReleaseTests.cs new file mode 100644 index 0000000000..bf620c4784 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoDeployReleaseTests.cs @@ -0,0 +1,444 @@ +using System; +using System.Collections.Generic; +using Cake.Common.Tests.Fixtures.Tools; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.OctopusDeploy +{ + public sealed class OctoDeployReleaseTests + { + private const string MinimalParameters = "deploy-release --project=\"MyProject\" --deployto=\"Testing\" --releasenumber=\"0.15.1\" --server http://octopus --apiKey API-12345"; + + public sealed class TheBaseArgumentBuilder + { + [Fact] + public void Should_Throw_If_Server_Is_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Server = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "server"); + } + + [Fact] + public void Should_Throw_If_Api_Key_Is_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.ApiKey = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "apiKey"); + } + + [Fact] + public void Should_Throw_If_ProjectName_Is_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Project = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "projectName"); + } + + [Fact] + public void Should_Throw_If_DeployTo_Is_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.DeployTo = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "deployTo"); + } + + [Fact] + public void Should_Throw_If_ReleaseNumber_Is_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.ReleaseNumber = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "releaseNumber"); + } + + [Fact] + public void Should_Throw_If_Settings_Is_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "settings"); + } + + [Fact] + public void Should_Give_Default_Minimal_Parameters() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters, result.Args); + } + + [Fact] + public void Should_Add_Username_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.Username = "mike123"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --user \"mike123\"", result.Args); + } + + [Fact] + public void Should_Add_Password_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.Password = "secret"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --pass \"secret\"", result.Args); + } + + [Fact] + public void Should_Add_Configuration_File_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.ConfigurationFile = "configFile.txt"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --configFile \"/Working/configFile.txt\"", result.Args); + } + + [Fact] + public void Should_Add_Debug_Flag_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.EnableDebugLogging = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --debug", result.Args); + } + + [Fact] + public void Should_Add_Ignore_Ssl_Errors_Flag_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.IgnoreSslErrors = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --ignoreSslErrors", result.Args); + } + + [Fact] + public void Should_Add_Enable_Service_Messages_Flag_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.EnableServiceMessages = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --enableServiceMessages", result.Args); + } + } + + public sealed class DeploymentArgumentBuilder + { + [Fact] + public void Should_Add_Progress_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.ShowProgress = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --progress", result.Args); + } + + [Fact] + public void Should_Add_FocePackageDownload_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.ForcePackageDownload = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --forcepackagedownload", result.Args); + } + + [Fact] + public void Should_Add_WaitForDeployment_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.WaitForDeployment = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --waitfordeployment", result.Args); + } + + [Fact] + public void Should_Add_DeploymentTimeout_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.DeploymentTimeout = TimeSpan.FromMinutes(1); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --deploymenttimeout=\"00:01:00\"", result.Args); + } + + [Fact] + public void Should_Add_CancelTimeout_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.CancelOnTimeout = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --cancelontimeout", result.Args); + } + + [Fact] + public void Should_Add_DeploymentChecksLeepCycle_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.DeploymentChecksLeepCycle = TimeSpan.FromMinutes(77); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --deploymentchecksleepcycle=\"01:17:00\"", result.Args); + } + + [Fact] + public void Should_Add_GuidedFailure_To_Arguments_If_True() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.GuidedFailure = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --guidedfailure=True", result.Args); + } + + [Fact] + public void Should_Add_GuidedFailure_To_Arguments_If_False() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.GuidedFailure = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --guidedfailure=True", result.Args); + } + + [Fact] + public void Should_Add_SpecificMachines_To_Arguments_If_NotNull() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.SpecificMachines = new string[] { "Machine1", "Machine2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --specificmachines=\"Machine1,Machine2\"", result.Args); + } + + [Fact] + public void Should_Add_Force_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.Force = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --force", result.Args); + } + + [Fact] + public void Should_Add_SkipSteps_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.SkipSteps = new[] { "Step1", "Step2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --skip=\"Step1\" --skip=\"Step2\"", result.Args); + } + + [Fact] + public void Should_Add_NoRawLog_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.NoRawLog = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --norawlog", result.Args); + } + + [Fact] + public void Should_Add_RawLogFile_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.RawLogFile = "someFile.txt"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --rawlogfile \"/Working/someFile.txt\"", result.Args); + } + + [Fact] + public void Should_Add_Variables_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.Variables.Add("var1", "value1"); + fixture.Settings.Variables.Add("var2", "value2"); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + + " --variable=\"var1:value1\"" + + " --variable=\"var2:value2\"", result.Args); + } + + [Fact] + public void Should_Add_DeployAt_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.DeployAt = new DateTime(2010, 6, 15).AddMinutes(1); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + " --deployat=\"2010-06-15 00:01\"", result.Args); + } + + [Fact] + public void Should_Add_Tenants_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.Tenant = new[] { "Tenant1", "Tenant2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + + " --tenant=\"Tenant1\"" + + " --tenant=\"Tenant2\"", result.Args); + } + + [Fact] + public void Should_Add_TenantTags_To_Arguments_If_Specified() + { + // Given + var fixture = new OctopusDeployReleaseDeployerFixture(); + fixture.Settings.TenantTags = new[] { "Tag1", "Tag2" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(MinimalParameters + + " --tenanttag=\"Tag1\"" + + " --tenanttag=\"Tag2\"", result.Args); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoPackTests.cs b/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoPackTests.cs new file mode 100644 index 0000000000..3cfdc9a10b --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/OctopusDeploy/OctoPackTests.cs @@ -0,0 +1,196 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tests.Fixtures.Tools; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.OctopusDeploy +{ + public sealed class OctoPackTests + { + public sealed class ThePackMethod + { + [Fact] + public void Should_Throw_If_Id_Is_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsArgumentNullException(result, "id"); + } + + [Fact] + public void Should_Add_Id_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage", result.Args); + } + + [Fact] + public void Should_Add_Version_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.Version = "1.2.3"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --version 1.2.3", result.Args); + } + + [Fact] + public void Should_Add_OutFolder_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.OutFolder = "out"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --outFolder \"/Working/out\"", result.Args); + } + + [Fact] + public void Should_Add_BasePath_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.BasePath = "base"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --basePath \"/Working/base\"", result.Args); + } + + [Fact] + public void Should_Add_Author_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.Author = "author"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --author \"author\"", result.Args); + } + + [Fact] + public void Should_Add_Title_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.Title = "title"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --title \"title\"", result.Args); + } + + [Fact] + public void Should_Add_Description_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.Description = "description"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --description \"description\"", result.Args); + } + + [Fact] + public void Should_Add_ReleaseNotes_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.ReleaseNotes = "releasenotes"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --releaseNotes \"releasenotes\"", result.Args); + } + + [Fact] + public void Should_Add_ReleaseNotesFile_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.ReleaseNotesFile = "releasenotes.md"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --releaseNotesFile \"/Working/releasenotes.md\"", result.Args); + } + + [Fact] + public void Should_Add_Include_To_Arguments_If_Not_Null() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.Include = new[] + { + "bin/*.dll", + "bin/*.pdb" + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --include \"bin/*.dll\" --include \"bin/*.pdb\"", result.Args); + } + + [Fact] + public void Should_Add_Overwrite_To_Arguments_If_True() + { + // Given + var fixture = new OctopusDeployPackerFixture(); + fixture.Id = "MyPackage"; + fixture.Settings.Overwrite = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("pack --id MyPackage --overwrite", result.Args); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Tools/Roundhouse/RoundhouseRunnerTests.cs b/src/Cake.Common.Tests/Unit/Tools/Roundhouse/RoundhouseRunnerTests.cs index 62de4a97a6..66fcaedd62 100644 --- a/src/Cake.Common.Tests/Unit/Tools/Roundhouse/RoundhouseRunnerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/Roundhouse/RoundhouseRunnerTests.cs @@ -158,12 +158,20 @@ public void Should_Execute_Process_With_Flags() fixture.Settings.Silent = true; fixture.Settings.WarnOnOneTimeScriptChanges = true; fixture.Settings.WithTransaction = true; + fixture.Settings.Baseline = true; + fixture.Settings.RunAllAnyTimeScripts = true; + fixture.Settings.SearchAllSubdirectoriesInsteadOfTraverse = true; + fixture.Settings.DisableTokenReplacement = true; + fixture.Settings.RunAllAnyTimeScripts = true; + fixture.Settings.Debug = true; + fixture.Settings.DisableOutput = true; + fixture.Settings.DoNotCreateDatabase = true; // When var result = fixture.Run(); // Then - Assert.Equal("--drop --dryrun --restore --silent --w --t", result.Args); + Assert.Equal("--drop --dryrun --restore --silent --baseline --searchallinsteadoftraverse --disabletokens --runallanytimescripts --debug --disableoutput --donotcreatedatabase --w --t", result.Args); } [Fact] diff --git a/src/Cake.Common.Tests/Unit/Tools/SignTool/SignToolSignRunnerTests.cs b/src/Cake.Common.Tests/Unit/Tools/SignTool/SignToolSignRunnerTests.cs index df1e2d14c1..418365321a 100644 --- a/src/Cake.Common.Tests/Unit/Tools/SignTool/SignToolSignRunnerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/SignTool/SignToolSignRunnerTests.cs @@ -4,6 +4,7 @@ using System; using Cake.Common.Tests.Fixtures.Tools; +using Cake.Common.Tools.SignTool; using Cake.Core; using Cake.Testing; using Xunit; @@ -99,7 +100,7 @@ public void Should_Throw_If_Assembly_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("SignTool SIGN: The assembly '/Working/a.dll' do not exist.", result?.Message); + Assert.Equal("SignTool SIGN: The assembly '/Working/a.dll' does not exist.", result?.Message); } [Fact] @@ -177,7 +178,7 @@ public void Should_Throw_If_Certificate_File_Do_Not_Exist() // Then Assert.IsType(result); - Assert.Equal("SignTool SIGN: The certificate '/Working/cert.pfx' do not exist.", result?.Message); + Assert.Equal("SignTool SIGN: The certificate '/Working/cert.pfx' does not exist.", result?.Message); } [Fact] @@ -279,6 +280,48 @@ public void Should_Call_Sign_Tool_With_Correct_Parameters_With_Thumbprint() // Then Assert.Equal("SIGN /t \"https://t.com/\" /sha1 \"ThumbprintTest\" \"/Working/a.dll\"", result.Args); } + + [Fact] + public void Should_Call_Sign_Tool_With_Correct_Parameters_With_Sha256_Digest_Algorithm() + { + // Given + var fixture = new SignToolSignRunnerFixture(); + fixture.Settings.DigestAlgorithm = SignToolDigestAlgorithm.Sha256; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("SIGN /fd sha256 /t \"https://t.com/\" /f \"/Working/cert.pfx\" /p secret \"/Working/a.dll\"", result.Args); + } + + [Fact] + public void Should_Call_Sign_Tool_With_Correct_Parameters_With_RFC6131_Timestamp_Uri_And_Sha256_Timestamp_Algorithm() + { + // Given + var fixture = new SignToolSignRunnerFixture(); + fixture.Settings.TimeStampDigestAlgorithm = SignToolDigestAlgorithm.Sha256; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("SIGN /tr \"https://t.com/\" /td sha256 /f \"/Working/cert.pfx\" /p secret \"/Working/a.dll\"", result.Args); + } + + [Fact] + public void Should_Call_Sign_Tool_With_Correct_Parameters_With_Append_Signature() + { + // Given + var fixture = new SignToolSignRunnerFixture(); + fixture.Settings.AppendSignature = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("SIGN /t \"https://t.com/\" /f \"/Working/cert.pfx\" /p secret /as \"/Working/a.dll\"", result.Args); + } } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporterTests.cs b/src/Cake.Common.Tests/Unit/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporterTests.cs index ca5936cff2..396e9ec10c 100644 --- a/src/Cake.Common.Tests/Unit/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporterTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporterTests.cs @@ -179,6 +179,79 @@ public void Should_Append_XsltFile() "/xsltFile:\"/Working/template.xslt\"", result.Args); } + [Fact] + public void Should_Rethrow_Exception_From_Action() + { + // Given + var exception = new CakeException("The exception message"); + var fixture = new SpecFlowTestExecutionReporterFixture(); + fixture.Settings.ThrowOnTestFailure = true; + var intercepting = true; + + fixture.Action = context => + { + context.ProcessRunner.Start( + new FilePath("/Working/tools/MSTest.exe"), + new ProcessSettings() + { + Arguments = "/resultsfile:\"/Working/TestResult.trx\"" + }); + + // Quick fix to avoid throwing exception while intercepting action + if (intercepting) + { + intercepting = false; + } + else + { + throw exception; + } + }; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + Assert.IsCakeException(result, exception.Message); + } + + [Fact] + public void Should_Not_Rethrow_Exception_From_Action() + { + // Given + var exception = new CakeException("The exception message"); + var fixture = new SpecFlowTestExecutionReporterFixture(); + fixture.Settings.ThrowOnTestFailure = false; + var intercepting = true; + + fixture.Action = context => + { + var process = context.ProcessRunner.Start( + new FilePath("/Working/tools/MSTest.exe"), + new ProcessSettings() + { + Arguments = "/resultsfile:\"/Working/TestResult.trx\"" + }); + + // Quick fix to avoid throwing exception while intercepting action + if (intercepting) + { + intercepting = false; + } + else + { + throw exception; + } + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("mstestexecutionreport \"/Working/Tests.csproj\" " + + "/testResult:\"/Working/TestResult.trx\"", result.Args); + } + [Fact] public void Should_Capture_XUnit2() { diff --git a/src/Cake.Common.Tests/Unit/Tools/VSTest/VSTestRunnerTests.cs b/src/Cake.Common.Tests/Unit/Tools/VSTest/VSTestRunnerTests.cs index 9c0129d4ed..a09d05a529 100644 --- a/src/Cake.Common.Tests/Unit/Tools/VSTest/VSTestRunnerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/VSTest/VSTestRunnerTests.cs @@ -153,7 +153,7 @@ public void Should_Throw_If_Process_Has_A_Non_Zero_Exit_Code() } [Fact] - public void Should_Not_Use_Isolation_By_Default() + public void Should_Have_No_Args_By_Default() { // Given var fixture = new VSTestRunnerFixture(); @@ -179,18 +179,74 @@ public void Should_Use_Isolation_If_Enabled_In_Settings() Assert.Equal("\"/Working/Test1.dll\" /InIsolation", result.Args); } + [Fact] + public void Should_Enable_UseVsixExtensions_If_Enabled_In_Settings() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.UseVsixExtensions = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /UseVsixExtensions:true", result.Args); + } + + [Fact] + public void Should_Disable_UseVsixExtensions_If_Disabled_In_Settings() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.UseVsixExtensions = false; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /UseVsixExtensions:false", result.Args); + } + + [Fact] + public void Should_Use_TestAdapterPath_If_Provided() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.TestAdapterPath = new DirectoryPath("Path to/test adapters"); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /TestAdapterPath:\"/Working/Path to/test adapters\"", result.Args); + } + [Fact] public void Should_Use_Logger_If_Provided() { // Given var fixture = new VSTestRunnerFixture(); - fixture.Settings.Logger = VSTestLogger.Trx; + fixture.Settings.Logger = "MyCustomLogger"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /Logger:MyCustomLogger", result.Args); + } + + [Fact] + public void Should_Use_Diag_If_Provided() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.Diag = new FilePath("Path to/diag log.txt"); // When var result = fixture.Run(); // Then - Assert.Equal("\"/Working/Test1.dll\" /Logger:trx", result.Args); + Assert.Equal("\"/Working/Test1.dll\" /Diag:\"/Working/Path to/diag log.txt\"", result.Args); } [Fact] @@ -204,7 +260,49 @@ public void Should_Use_SettingsFile_If_Provided() var result = fixture.Run(); // Then - Assert.Equal("\"/Working/Test1.dll\" /Settings:Local.RunSettings", result.Args); + Assert.Equal("\"/Working/Test1.dll\" /Settings:\"/Working/Local.RunSettings\"", result.Args); + } + + [Fact] + public void Should_Quote_Absolute_SettingsFile_Path() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.SettingsFile = new FilePath("Filename with spaces.RunSettings"); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /Settings:\"/Working/Filename with spaces.RunSettings\"", result.Args); + } + + [Fact] + public void Should_Use_Parallel_If_Enabled_In_Settings() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.Parallel = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /Parallel", result.Args); + } + + [Fact] + public void Should_Use_EnableCodeCoverage_If_Enabled_In_Settings() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.EnableCodeCoverage = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /EnableCodeCoverage", result.Args); } [Fact] @@ -235,6 +333,20 @@ public void Should_Use_FrameworkVersion_If_Provided() Assert.Equal("\"/Working/Test1.dll\" /Framework:Framework40", result.Args); } + [Fact] + public void Should_Use_TestCaseFilter_If_Provided() + { + // Given + var fixture = new VSTestRunnerFixture(); + fixture.Settings.TestCaseFilter = "(FullyQualifiedName~Nightly|Name=MyTestMethod)"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"/Working/Test1.dll\" /TestCaseFilter:\"(FullyQualifiedName~Nightly|Name=MyTestMethod)\"", result.Args); + } + [Fact] public void Should_Add_FilePath_For_Each_Assembly() { diff --git a/src/Cake.Common.Tests/project.json b/src/Cake.Common.Tests/project.json index 611387dc8f..0b51cdd0f9 100644 --- a/src/Cake.Common.Tests/project.json +++ b/src/Cake.Common.Tests/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "buildOptions": { "platform": "AnyCpu", "additionalArguments": [ diff --git a/src/Cake.Common/Build/AppVeyor/AppVeyorProvider.cs b/src/Cake.Common/Build/AppVeyor/AppVeyorProvider.cs index a7a3c9974d..234cf03443 100644 --- a/src/Cake.Common/Build/AppVeyor/AppVeyorProvider.cs +++ b/src/Cake.Common/Build/AppVeyor/AppVeyorProvider.cs @@ -29,6 +29,32 @@ public sealed class AppVeyorProvider : IAppVeyorProvider /// /// true if the current build is running on AppVeyor.; otherwise, false. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information("Running on AppVeyor"); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information("Running on AppVeyor"); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public bool IsRunningOnAppVeyor => !string.IsNullOrWhiteSpace(_environment.GetEnvironmentVariable("APPVEYOR")); /// @@ -37,6 +63,60 @@ public sealed class AppVeyorProvider : IAppVeyorProvider /// /// The AppVeyor environment. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Environment: + /// ApiUrl: {0} + /// Configuration: {1} + /// JobId: {2} + /// JobName: {3} + /// Platform: {4} + /// ScheduledBuild: {5}", + /// BuildSystem.AppVeyor.Environment.ApiUrl, + /// BuildSystem.AppVeyor.Environment.Configuration, + /// BuildSystem.AppVeyor.Environment.JobId, + /// BuildSystem.AppVeyor.Environment.JobName, + /// BuildSystem.AppVeyor.Environment.Platform, + /// BuildSystem.AppVeyor.Environment.ScheduledBuild + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Environment: + /// ApiUrl: {0} + /// Configuration: {1} + /// JobId: {2} + /// JobName: {3} + /// Platform: {4} + /// ScheduledBuild: {5}", + /// AppVeyor.Environment.ApiUrl, + /// AppVeyor.Environment.Configuration, + /// AppVeyor.Environment.JobId, + /// AppVeyor.Environment.JobName, + /// AppVeyor.Environment.Platform, + /// AppVeyor.Environment.ScheduledBuild + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorEnvironmentInfo Environment { get; } /// @@ -114,8 +194,7 @@ public void UploadArtifact(FilePath path, AppVeyorUploadArtifactsSettings settin arguments.AppendQuoted(settings.DeploymentName); } - // Start the process. - _processRunner.Start("appveyor", new ProcessSettings { Arguments = arguments }); + StartAppVeyor(arguments); } /// @@ -177,6 +256,32 @@ public void UploadTestResults(FilePath path, AppVeyorTestResultsType resultsType /// Updates the build version. /// /// The new build version. + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// BuildSystem.AppVeyor.UpdateBuildVersion("2.0.0.0"); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// AppVeyor.UpdateBuildVersion("2.0.0.0"); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public void UpdateBuildVersion(string version) { if (version == null) @@ -199,8 +304,7 @@ public void UpdateBuildVersion(string version) arguments.Append("-Version"); arguments.AppendQuoted(version); - // Start the process. - _processRunner.Start("appveyor", new ProcessSettings { Arguments = arguments }); + StartAppVeyor(arguments); } /// @@ -209,6 +313,64 @@ public void UpdateBuildVersion(string version) /// A short message to display /// The category of the message /// Additional message details + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// BuildSystem.AppVeyor.AddMessage( + /// "This is a error message.", + /// AppVeyorMessageCategoryType.Error, + /// "Error details." + /// ); + /// + /// BuildSystem.AppVeyor.AddMessage( + /// "This is a information message.", + /// AppVeyorMessageCategoryType.Information, + /// "Information details." + /// ); + /// + /// BuildSystem.AppVeyor.AddMessage( + /// "This is a warning message.", + /// AppVeyorMessageCategoryType.Warning, + /// "Warning details." + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// AppVeyor.AddMessage( + /// "This is a error message.", + /// AppVeyorMessageCategoryType.Error, + /// "Error details." + /// ); + /// + /// AppVeyor.AddMessage( + /// "This is a information message.", + /// AppVeyorMessageCategoryType.Information, + /// "Information details." + /// ); + /// + /// AppVeyor.AddMessage( + /// "This is a warning message.", + /// AppVeyorMessageCategoryType.Warning, + /// "Warning details." + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public void AddMessage(string message, AppVeyorMessageCategoryType category = AppVeyorMessageCategoryType.Information, string details = null) { if (message == null) @@ -238,8 +400,18 @@ public void AddMessage(string message, AppVeyorMessageCategoryType category = Ap arguments.AppendQuoted(details); } - // Start the process. - _processRunner.Start("appveyor", new ProcessSettings { Arguments = arguments }); + StartAppVeyor(arguments); + } + + private void StartAppVeyor(ProcessArgumentBuilder arguments, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") + { + var process = _processRunner.Start("appveyor", new ProcessSettings { Arguments = arguments }); + process.WaitForExit(); + var exitCode = process.GetExitCode(); + if (exitCode != 0) + { + throw new CakeException($"{memberName} failed ({exitCode})."); + } } } } \ No newline at end of file diff --git a/src/Cake.Common/Build/AppVeyor/Data/AppVeyorEnvironmentInfo.cs b/src/Cake.Common/Build/AppVeyor/Data/AppVeyorEnvironmentInfo.cs index 74dabcc8dd..e9e59216bd 100644 --- a/src/Cake.Common/Build/AppVeyor/Data/AppVeyorEnvironmentInfo.cs +++ b/src/Cake.Common/Build/AppVeyor/Data/AppVeyorEnvironmentInfo.cs @@ -65,6 +65,49 @@ public sealed class AppVeyorEnvironmentInfo : AppVeyorInfo /// /// The AppVeyor project information. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Project: + /// Id: {0} + /// Name: {1} + /// Slug: {2}", + /// BuildSystem.AppVeyor.Environment.Project.Id, + /// BuildSystem.AppVeyor.Environment.Project.Name, + /// BuildSystem.AppVeyor.Environment.Project.Slug + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// // via appveyor + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Project: + /// Id: {0} + /// Name: {1} + /// Slug: {2}", + /// AppVeyor.Environment.Project.Id, + /// AppVeyor.Environment.Project.Name, + /// AppVeyor.Environment.Project.Slug + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorProjectInfo Project { get; } /// @@ -73,6 +116,52 @@ public sealed class AppVeyorEnvironmentInfo : AppVeyorInfo /// /// The AppVeyor build information. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Build: + /// Folder: {0} + /// Id: {1} + /// Number: {2} + /// Version: {3}", + /// BuildSystem.AppVeyor.Environment.Build.Folder, + /// BuildSystem.AppVeyor.Environment.Build.Id, + /// BuildSystem.AppVeyor.Environment.Build.Number, + /// BuildSystem.AppVeyor.Environment.Build.Version + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Build: + /// Folder: {0} + /// Id: {1} + /// Number: {2} + /// Version: {3}", + /// AppVeyor.Environment.Build.Folder, + /// AppVeyor.Environment.Build.Id, + /// AppVeyor.Environment.Build.Number, + /// AppVeyor.Environment.Build.Version + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorBuildInfo Build { get; } /// @@ -81,6 +170,48 @@ public sealed class AppVeyorEnvironmentInfo : AppVeyorInfo /// /// The AppVeyor pull request information. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"PullRequest: + /// IsPullRequest: {0} + /// Number: {1} + /// Title: {2}", + /// BuildSystem.AppVeyor.Environment.PullRequest.IsPullRequest, + /// BuildSystem.AppVeyor.Environment.PullRequest.Number, + /// BuildSystem.AppVeyor.Environment.PullRequest.Title + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"PullRequest: + /// IsPullRequest: {0} + /// Number: {1} + /// Title: {2}", + /// AppVeyor.Environment.PullRequest.IsPullRequest, + /// AppVeyor.Environment.PullRequest.Number, + /// AppVeyor.Environment.PullRequest.Title + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorPullRequestInfo PullRequest { get; } /// @@ -89,6 +220,52 @@ public sealed class AppVeyorEnvironmentInfo : AppVeyorInfo /// /// The AppVeyor repository information. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Repository: + /// Branch: {0} + /// Name: {1} + /// Provider: {2} + /// Scm: {3}", + /// BuildSystem.AppVeyor.Environment.Repository.Branch, + /// BuildSystem.AppVeyor.Environment.Repository.Name, + /// BuildSystem.AppVeyor.Environment.Repository.Provider, + /// BuildSystem.AppVeyor.Environment.Repository.Scm + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Repository: + /// Branch: {0} + /// Name: {1} + /// Provider: {2} + /// Scm: {3}", + /// AppVeyor.Environment.Repository.Branch, + /// AppVeyor.Environment.Repository.Name, + /// AppVeyor.Environment.Repository.Provider, + /// AppVeyor.Environment.Repository.Scm + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorRepositoryInfo Repository { get; } /// diff --git a/src/Cake.Common/Build/AppVeyor/Data/AppVeyorRepositoryInfo.cs b/src/Cake.Common/Build/AppVeyor/Data/AppVeyorRepositoryInfo.cs index 220e489d32..f4fb9fe0af 100644 --- a/src/Cake.Common/Build/AppVeyor/Data/AppVeyorRepositoryInfo.cs +++ b/src/Cake.Common/Build/AppVeyor/Data/AppVeyorRepositoryInfo.cs @@ -23,6 +23,12 @@ public sealed class AppVeyorRepositoryInfo : AppVeyorInfo /// /// kiln /// + /// + /// vso + /// + /// + /// gitlab + /// /// /// /// @@ -68,6 +74,44 @@ public sealed class AppVeyorRepositoryInfo : AppVeyorInfo /// /// The tag information for the build. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Repository: + /// IsTag: {0} + /// Name: {1}", + /// BuildSystem.AppVeyor.Environment.Repository.Tag.IsTag, + /// BuildSystem.AppVeyor.Environment.Repository.Tag.Name + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Repository: + /// IsTag: {0} + /// Name: {1}", + /// AppVeyor.Environment.Repository.Tag.IsTag, + /// AppVeyor.Environment.Repository.Tag.Name + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorTagInfo Tag { get; } /// @@ -76,6 +120,60 @@ public sealed class AppVeyorRepositoryInfo : AppVeyorInfo /// /// The commit information for the build. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Repository: + /// Author: {0} + /// Email: {1} + /// ExtendedMessage: {2} + /// Id: {3} + /// Message: {4} + /// Timestamp: {5}", + /// BuildSystem.AppVeyor.Environment.Repository.Commit.Author, + /// BuildSystem.AppVeyor.Environment.Repository.Commit.Email, + /// BuildSystem.AppVeyor.Environment.Repository.Commit.ExtendedMessage, + /// BuildSystem.AppVeyor.Environment.Repository.Commit.Id, + /// BuildSystem.AppVeyor.Environment.Repository.Commit.Message, + /// BuildSystem.AppVeyor.Environment.Repository.Commit.Timestamp + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Repository: + /// Author: {0} + /// Email: {1} + /// ExtendedMessage: {2} + /// Id: {3} + /// Message: {4} + /// Timestamp: {5}", + /// AppVeyor.Environment.Repository.Commit.Author, + /// AppVeyor.Environment.Repository.Commit.Email, + /// AppVeyor.Environment.Repository.Commit.ExtendedMessage, + /// AppVeyor.Environment.Repository.Commit.Id, + /// AppVeyor.Environment.Repository.Commit.Message, + /// AppVeyor.Environment.Repository.Commit.Timestamp + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// public AppVeyorCommitInfo Commit { get; } /// diff --git a/src/Cake.Common/Build/AppVeyor/IAppVeyorProvider.cs b/src/Cake.Common/Build/AppVeyor/IAppVeyorProvider.cs index 63f0e5d158..576c6a05ea 100644 --- a/src/Cake.Common/Build/AppVeyor/IAppVeyorProvider.cs +++ b/src/Cake.Common/Build/AppVeyor/IAppVeyorProvider.cs @@ -19,6 +19,32 @@ public interface IAppVeyorProvider /// /// true if the current build is running on AppVeyor.; otherwise, false. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information("Running on AppVeyor"); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information("Running on AppVeyor"); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// bool IsRunningOnAppVeyor { get; } /// @@ -27,6 +53,60 @@ public interface IAppVeyorProvider /// /// The AppVeyor environment. /// + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Environment: + /// ApiUrl: {0} + /// Configuration: {1} + /// JobId: {2} + /// JobName: {3} + /// Platform: {4} + /// ScheduledBuild: {5}", + /// BuildSystem.AppVeyor.Environment.ApiUrl, + /// BuildSystem.AppVeyor.Environment.Configuration, + /// BuildSystem.AppVeyor.Environment.JobId, + /// BuildSystem.AppVeyor.Environment.JobName, + /// BuildSystem.AppVeyor.Environment.Platform, + /// BuildSystem.AppVeyor.Environment.ScheduledBuild + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// Information( + /// @"Environment: + /// ApiUrl: {0} + /// Configuration: {1} + /// JobId: {2} + /// JobName: {3} + /// Platform: {4} + /// ScheduledBuild: {5}", + /// AppVeyor.Environment.ApiUrl, + /// AppVeyor.Environment.Configuration, + /// AppVeyor.Environment.JobId, + /// AppVeyor.Environment.JobName, + /// AppVeyor.Environment.Platform, + /// AppVeyor.Environment.ScheduledBuild + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// AppVeyorEnvironmentInfo Environment { get; } /// @@ -68,6 +148,64 @@ public interface IAppVeyorProvider /// A short message to display /// The category of the message /// Additional message details + /// Via BuildSystem + /// + /// + /// if (BuildSystem.AppVeyor.IsRunningOnAppVeyor) + /// { + /// BuildSystem.AppVeyor.AddMessage( + /// "This is a error message.", + /// AppVeyorMessageCategoryType.Error, + /// "Error details." + /// ); + /// + /// BuildSystem.AppVeyor.AddMessage( + /// "This is a information message.", + /// AppVeyorMessageCategoryType.Information, + /// "Information details." + /// ); + /// + /// BuildSystem.AppVeyor.AddMessage( + /// "This is a warning message.", + /// AppVeyorMessageCategoryType.Warning, + /// "Warning details." + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// + /// Via AppVeyor + /// + /// + /// if (AppVeyor.IsRunningOnAppVeyor) + /// { + /// AppVeyor.AddMessage( + /// "This is a error message.", + /// AppVeyorMessageCategoryType.Error, + /// "Error details." + /// ); + /// + /// AppVeyor.AddMessage( + /// "This is a information message.", + /// AppVeyorMessageCategoryType.Information, + /// "Information details." + /// ); + /// + /// AppVeyor.AddMessage( + /// "This is a warning message.", + /// AppVeyorMessageCategoryType.Warning, + /// "Warning details." + /// ); + /// } + /// else + /// { + /// Information("Not running on AppVeyor"); + /// } + /// + /// void AddMessage(string message, AppVeyorMessageCategoryType category = AppVeyorMessageCategoryType.Information, string details = null); } } \ No newline at end of file diff --git a/src/Cake.Common/Build/Bamboo/Data/BambooPlanInfo.cs b/src/Cake.Common/Build/Bamboo/Data/BambooPlanInfo.cs index a13aa5eaac..e182eaf5d0 100644 --- a/src/Cake.Common/Build/Bamboo/Data/BambooPlanInfo.cs +++ b/src/Cake.Common/Build/Bamboo/Data/BambooPlanInfo.cs @@ -23,7 +23,7 @@ public sealed class BambooPlanInfo : BambooInfo /// Gets the Bamboo short Plan Name /// /// - /// The Bamboo Plan Name in it's short form. + /// The Bamboo Plan Name in its short form. /// public string ShortPlanName => GetEnvironmentString("bamboo_shortPlanName"); @@ -39,7 +39,7 @@ public sealed class BambooPlanInfo : BambooInfo /// Gets the Bamboo short Plan Key. /// /// - /// The Bamboo Plan Key in it's hort form. + /// The Bamboo Plan Key in its short form. /// public string ShortPlanKey => GetEnvironmentString("bamboo_shortPlanKey"); @@ -47,7 +47,7 @@ public sealed class BambooPlanInfo : BambooInfo /// Gets the Bamboo short job key. /// /// - /// The Bamboo job key in it's short form. + /// The Bamboo job key in its short form. /// public string ShortJobKey => GetEnvironmentString("bamboo_shortJobKey"); @@ -55,7 +55,7 @@ public sealed class BambooPlanInfo : BambooInfo /// Gets the Bamboo short Job Name. /// /// - /// The Bamboo Job Name in it's short form. + /// The Bamboo Job Name in its short form. /// public string ShortJobName => GetEnvironmentString("bamboo_shortJobName"); diff --git a/src/Cake.Common/Build/BuildSystem.cs b/src/Cake.Common/Build/BuildSystem.cs index f75e5c38ec..a3c29f18dc 100644 --- a/src/Cake.Common/Build/BuildSystem.cs +++ b/src/Cake.Common/Build/BuildSystem.cs @@ -8,9 +8,12 @@ using Cake.Common.Build.BitbucketPipelines; using Cake.Common.Build.Bitrise; using Cake.Common.Build.ContinuaCI; +using Cake.Common.Build.GitLabCI; +using Cake.Common.Build.GoCD; using Cake.Common.Build.Jenkins; using Cake.Common.Build.MyGet; using Cake.Common.Build.TeamCity; +using Cake.Common.Build.TFBuild; using Cake.Common.Build.TravisCI; namespace Cake.Common.Build @@ -33,7 +36,22 @@ public sealed class BuildSystem /// The Bitrise Provider. /// The Travis CI provider. /// The Bitbucket Pipelines provider. - public BuildSystem(IAppVeyorProvider appVeyorProvider, ITeamCityProvider teamCityProvider, IMyGetProvider myGetProvider, IBambooProvider bambooProvider, IContinuaCIProvider continuaCIProvider, IJenkinsProvider jenkinsProvider, IBitriseProvider bitriseProvider, ITravisCIProvider travisCIProvider, IBitbucketPipelinesProvider bitbucketPipelinesProvider) + /// The Go.CD provider. + /// The GitLab CI provider. + /// The TF Build provider. + public BuildSystem( + IAppVeyorProvider appVeyorProvider, + ITeamCityProvider teamCityProvider, + IMyGetProvider myGetProvider, + IBambooProvider bambooProvider, + IContinuaCIProvider continuaCIProvider, + IJenkinsProvider jenkinsProvider, + IBitriseProvider bitriseProvider, + ITravisCIProvider travisCIProvider, + IBitbucketPipelinesProvider bitbucketPipelinesProvider, + IGoCDProvider goCDProvider, + IGitLabCIProvider gitlabCIProvider, + ITFBuildProvider tfBuildProvider) { if (appVeyorProvider == null) { @@ -71,6 +89,18 @@ public BuildSystem(IAppVeyorProvider appVeyorProvider, ITeamCityProvider teamCit { throw new ArgumentNullException(nameof(bitbucketPipelinesProvider)); } + if (goCDProvider == null) + { + throw new ArgumentNullException(nameof(goCDProvider)); + } + if (gitlabCIProvider == null) + { + throw new ArgumentNullException(nameof(gitlabCIProvider)); + } + if (tfBuildProvider == null) + { + throw new ArgumentNullException(nameof(tfBuildProvider)); + } AppVeyor = appVeyorProvider; TeamCity = teamCityProvider; @@ -81,6 +111,9 @@ public BuildSystem(IAppVeyorProvider appVeyorProvider, ITeamCityProvider teamCit Bitrise = bitriseProvider; TravisCI = travisCIProvider; BitbucketPipelines = bitbucketPipelinesProvider; + GoCD = goCDProvider; + GitLabCI = gitlabCIProvider; + TFBuild = tfBuildProvider; } /// @@ -368,6 +401,116 @@ public BuildSystem(IAppVeyorProvider appVeyorProvider, ITeamCityProvider teamCit /// public IBitbucketPipelinesProvider BitbucketPipelines { get; } + /// + /// Gets a value indicating whether the current build is running on Go.CD. + /// + /// + /// + /// if(BuildSystem.IsRunningOnGoCD) + /// { + /// // Get the build counter. + /// var counter = BuildSystem.GoCD.Environment.Pipeline.Counter; + /// } + /// + /// + /// + /// true if the build currently is running on Go.CD; otherwise, false. + /// + public bool IsRunningOnGoCD => GoCD.IsRunningOnGoCD; + + /// + /// Gets the Go.CD Provider. + /// + /// + /// + /// if(BuildSystem.IsRunningOnGoCD) + /// { + /// // Get the pipeline counter. + /// var counter = BuildSystem.GoCD.Environment.Environment.Pipeline.Counter; + /// } + /// + /// + public IGoCDProvider GoCD { get; } + + /// + /// Gets the GitLab CI Provider. + /// + /// + /// + /// if(BuildSystem.IsRunningOnGitLabCI) + /// { + /// // Get the build commit hash. + /// var commitHash = BuildSystem.GitLabCI.Environment.Build.Reference; + /// } + /// + /// + public IGitLabCIProvider GitLabCI { get; } + + /// + /// Gets a value indicating whether this instance is running on GitLab CI. + /// + /// + /// + /// if(BuildSystem.IsRunningOnGitLabCI) + /// { + /// // Get the build commit hash. + /// var commitHash = BuildSystem.GitLabCI.Environment.Build.Reference; + /// } + /// + /// + /// + /// true if this instance is running on GitLab CI; otherwise, false. + /// + public bool IsRunningOnGitLabCI => GitLabCI.IsRunningOnGitLabCI; + + /// + /// Gets a value indicating whether this instance is running on VSTS. + /// + /// + /// + /// if(BuildSystem.IsRunningOnVSTS) + /// { + /// // Get the build commit hash. + /// var commitHash = BuildSystem.TFBuild.Environment.Repository.SourceVersion; + /// } + /// + /// + /// + /// true if this instance is running on VSTS; otherwise, false. + /// + public bool IsRunningOnVSTS => TFBuild.IsRunningOnVSTS; + + /// + /// Gets a value indicating whether this instance is running on TFS. + /// + /// + /// + /// if(BuildSystem.IsRunningOnTFS) + /// { + /// // Get the build commit hash. + /// var commitHash = BuildSystem.TFBuild.Environment.Repository.SourceVersion; + /// } + /// + /// + /// + /// true if this instance is running on TFS; otherwise, false. + /// + public bool IsRunningOnTFS => TFBuild.IsRunningOnTFS; + + /// + /// Gets the TF Build Provider. + /// + /// + /// + /// if(BuildSystem.IsRunningOnVSTS) + /// { + /// // Get the build definition name. + /// var definitionName = BuildSystem.TFBuild.Environment.BuildDefinition.Name; + /// } + /// + /// + public ITFBuildProvider TFBuild { get; } + /// /// Gets a value indicating whether the current build is local build. /// @@ -387,6 +530,6 @@ public BuildSystem(IAppVeyorProvider appVeyorProvider, ITeamCityProvider teamCit /// /// true if the current build is local build; otherwise, false. /// - public bool IsLocalBuild => !(IsRunningOnAppVeyor || IsRunningOnTeamCity || IsRunningOnMyGet || IsRunningOnBamboo || IsRunningOnContinuaCI || IsRunningOnJenkins || IsRunningOnBitrise || IsRunningOnTravisCI || IsRunningOnBitbucketPipelines); + public bool IsLocalBuild => !(IsRunningOnAppVeyor || IsRunningOnTeamCity || IsRunningOnMyGet || IsRunningOnBamboo || IsRunningOnContinuaCI || IsRunningOnJenkins || IsRunningOnBitrise || IsRunningOnTravisCI || IsRunningOnBitbucketPipelines || IsRunningOnGoCD || IsRunningOnGitLabCI || IsRunningOnTFS || IsRunningOnVSTS); } } \ No newline at end of file diff --git a/src/Cake.Common/Build/BuildSystemAliases.cs b/src/Cake.Common/Build/BuildSystemAliases.cs index e95f8b98fa..9273d2cc96 100644 --- a/src/Cake.Common/Build/BuildSystemAliases.cs +++ b/src/Cake.Common/Build/BuildSystemAliases.cs @@ -8,9 +8,12 @@ using Cake.Common.Build.BitbucketPipelines; using Cake.Common.Build.Bitrise; using Cake.Common.Build.ContinuaCI; +using Cake.Common.Build.GitLabCI; +using Cake.Common.Build.GoCD; using Cake.Common.Build.Jenkins; using Cake.Common.Build.MyGet; using Cake.Common.Build.TeamCity; +using Cake.Common.Build.TFBuild; using Cake.Common.Build.TravisCI; using Cake.Core; using Cake.Core.Annotations; @@ -50,8 +53,10 @@ public static BuildSystem BuildSystem(this ICakeContext context) var bitriseProvider = new BitriseProvider(context.Environment); var travisCIProvider = new TravisCIProvider(context.Environment, context.Log); var bitbucketPipelinesProvider = new BitbucketPipelinesProvider(context.Environment); - - return new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider); + var goCDProvider = new GoCDProvider(context.Environment, context.Log); + var gitlabCIProvider = new GitLabCIProvider(context.Environment); + var tfBuildProvider = new TFBuildProvider(context.Environment); + return new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitlabCIProvider, tfBuildProvider); } /// @@ -174,7 +179,7 @@ public static IContinuaCIProvider ContinuaCI(this ICakeContext context) } /// - /// Gets a instance that can be user to + /// Gets a instance that can be used to /// obtain information from the Jenkins environment. /// /// @@ -199,7 +204,7 @@ public static IJenkinsProvider Jenkins(this ICakeContext context) } /// - /// Gets a instance that can be user to + /// Gets a instance that can be used to /// obtain information from the Bitrise environment. /// /// @@ -224,7 +229,7 @@ public static IBitriseProvider Bitrise(this ICakeContext context) } /// - /// Gets a instance that can be user to + /// Gets a instance that can be used to /// obtain information from the Travis CI environment. /// /// @@ -249,7 +254,7 @@ public static ITravisCIProvider TravisCI(this ICakeContext context) } /// - /// Gets a instance that can be user to + /// Gets a instance that can be used to /// obtain information from the Bitbucket Pipelines environment. /// /// @@ -272,5 +277,80 @@ public static IBitbucketPipelinesProvider BitbucketPipelines(this ICakeContext c var buildSystem = context.BuildSystem(); return buildSystem.BitbucketPipelines; } + + /// + /// Gets a instance that can be used to + /// obtain information from the Go.CD environment. + /// + /// + /// + /// var isGoCDBuild = GoCD.IsRunningOnGoCD; + /// + /// + /// The context. + /// A instance. + [CakePropertyAlias(Cache = true)] + [CakeNamespaceImport("Cake.Common.Build.GoCD")] + [CakeNamespaceImport("Cake.Common.Build.GoCD.Data")] + public static IGoCDProvider GoCD(this ICakeContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var buildSystem = context.BuildSystem(); + return buildSystem.GoCD; + } + + /// + /// Gets a instance that can be used to + /// obtain information from the GitLab CI environment. + /// + /// + /// + /// var isGitLabCIBuild = GitLabCI.IsRunningOnGitLabCI; + /// + /// + /// The context. + /// A instance. + [CakePropertyAlias(Cache = true)] + [CakeNamespaceImport("Cake.Common.Build.GitLabCI")] + [CakeNamespaceImport("Cake.Common.Build.GitLabCI.Data")] + public static IGitLabCIProvider GitLabCI(this ICakeContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var buildSystem = context.BuildSystem(); + return buildSystem.GitLabCI; + } + + /// + /// Gets a instance that can be used to + /// obtain information from the Team Foundation Build environment. + /// + /// + /// + /// var isTFSBuild = TFBuild.IsRunningOnTFS; + /// + /// + /// The context. + /// A instance. + [CakePropertyAlias(Cache = true)] + [CakeNamespaceImport("Cake.Common.Build.TFBuild")] + [CakeNamespaceImport("Cake.Common.Build.TFBuild.Data")] + public static ITFBuildProvider TFBuild(this ICakeContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var buildSystem = context.BuildSystem(); + return buildSystem.TFBuild; + } } } \ No newline at end of file diff --git a/src/Cake.Common/Build/GitLabCI/Data/GitLabCIBuildInfo.cs b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIBuildInfo.cs new file mode 100644 index 0000000000..f01e352f59 --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIBuildInfo.cs @@ -0,0 +1,127 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI.Data +{ + /// + /// Provide GitLab CI build information for a current build + /// + public sealed class GitLabCIBuildInfo : GitLabCIInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GitLabCIBuildInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the unique id of the current build that GitLab CI uses internally. + /// + /// + /// The build ID. + /// + public int Id => GetEnvironmentInteger("CI_BUILD_ID"); + + /// + /// Gets the commit revision for which project is built. + /// + /// + /// The commit revision hash. + /// + public string Reference => GetEnvironmentString("CI_BUILD_REF"); + + /// + /// Gets the commit tag name. Present only when building tags. + /// + /// + /// The build tag name. + /// + public string Tag => GetEnvironmentString("CI_BUILD_TAG"); + + /// + /// Gets the name of the build as defined in .gitlab-ci.yml. + /// + /// + /// The name of the build. + /// + public string Name => GetEnvironmentString("CI_BUILD_NAME"); + + /// + /// Gets the name of the stage as defined in .gitlab-ci.yml. + /// + /// + /// The name of the current stage. + /// + public string Stage => GetEnvironmentString("CI_BUILD_STAGE"); + + /// + /// Gets the branch or tag name for which project is built. + /// + /// + /// The branch or tag for this build. + /// + public string RefName => GetEnvironmentString("CI_BUILD_REF_NAME"); + + /// + /// Gets the URL to clone the Git repository. + /// + /// + /// The repository URL. + /// + public string RepoUrl => GetEnvironmentString("CI_BUILD_REPO"); + + /// + /// Gets a value indicating whether the build was triggered. + /// + /// + /// True if the build was triggered, otherwise false. + /// + public bool Triggered => GetEnvironmentBoolean("CI_BUILD_TRIGGERED"); + + /// + /// Gets a value indicating whether the build was manually started. + /// + /// + /// True if the build was started manually, otherwise false. + /// + public bool Manual => GetEnvironmentBoolean("CI_BUILD_MANUAL"); + + /// + /// Gets the token used for authenticating with the GitLab Container Registry. + /// + /// + /// The build authorisation token. + /// + public string Token => GetEnvironmentString("CI_BUILD_TOKEN"); + + /// + /// Gets the unique id of the current pipeline that GitLab CI uses internally. + /// + /// + /// The unique build ID. + /// + public int PipelineId => GetEnvironmentInteger("CI_PIPELINE_ID"); + + /// + /// Gets the id of the user who started the build. + /// + /// + /// The user ID. + /// + public int UserId => GetEnvironmentInteger("GITLAB_USER_ID"); + + /// + /// Gets the email of the user who started the build. + /// + /// + /// The email address of the user. + /// + public string UserEmail => GetEnvironmentString("GITLAB_USER_EMAIL"); + } +} diff --git a/src/Cake.Common/Build/GitLabCI/Data/GitLabCIEnvironmentInfo.cs b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIEnvironmentInfo.cs new file mode 100644 index 0000000000..01a37258ff --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIEnvironmentInfo.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI.Data +{ + /// + /// Provides GitLab CI environment information for a current build. + /// + public sealed class GitLabCIEnvironmentInfo : GitLabCIInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GitLabCIEnvironmentInfo(ICakeEnvironment environment) + : base(environment) + { + Server = new GitLabCIServerInfo(environment); + Build = new Data.GitLabCIBuildInfo(environment); + Project = new Data.GitLabCIProjectInfo(environment); + Runner = new Data.GitLabCIRunnerInfo(environment); + } + + /// + /// Gets the GitLab CI runner information. + /// + /// + /// The GitLab CI runner information. + /// + public GitLabCIRunnerInfo Runner { get; } + + /// + /// Gets the GitLab CI server information. + /// + /// + /// The GitLab CI server information. + /// + public GitLabCIServerInfo Server { get; } + + /// + /// Gets the GitLab CI build information. + /// + /// + /// The GitLab CI build information. + /// + public GitLabCIBuildInfo Build { get; } + + /// + /// Gets the GitLab CI project information. + /// + /// + /// The GitLab CI project information. + /// + public GitLabCIProjectInfo Project { get; } + } +} diff --git a/src/Cake.Common/Build/GitLabCI/Data/GitLabCIProjectInfo.cs b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIProjectInfo.cs new file mode 100644 index 0000000000..e64a058514 --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIProjectInfo.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI.Data +{ + /// + /// Provides GitLab CI project information for a current build + /// + public sealed class GitLabCIProjectInfo : GitLabCIInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GitLabCIProjectInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the unique id of the current project that GitLab CI uses internally. + /// + /// + /// The project ID. + /// + public int Id => GetEnvironmentInteger("CI_PROJECT_ID"); + + /// + /// Gets the project name that is currently being built. + /// + /// + /// The project name. + /// + public string Name => GetEnvironmentString("CI_PROJECT_NAME"); + + /// + /// Gets the project namespace (username or groupname) that is currently being built. + /// + /// + /// The project namespace. + /// + public string Namespace => GetEnvironmentString("CI_PROJECT_NAMESPACE"); + + /// + /// Gets the namespace with project name. + /// + /// + /// The project namespace and project name. + /// + public string Path => GetEnvironmentString("CI_PROJECT_PATH"); + + /// + /// Gets the HTTP address to access the project. + /// + /// + /// The HTTP address to access the project. + /// + public string Url => GetEnvironmentString("CI_PROJECT_URL"); + + /// + /// Gets the full path where the repository is cloned and where the build is run. + /// + /// + /// The full path where the repository is cloned and where the build is run. + /// + public string Directory => GetEnvironmentString("CI_PROJECT_DIR"); + } +} diff --git a/src/Cake.Common/Build/GitLabCI/Data/GitLabCIRunnerInfo.cs b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIRunnerInfo.cs new file mode 100644 index 0000000000..dbc03df2fb --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIRunnerInfo.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI.Data +{ + /// + /// Provides GitLab CI runner information for a current build. + /// + public sealed class GitLabCIRunnerInfo : GitLabCIInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GitLabCIRunnerInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the unique id of runner being used. + /// + /// + /// The unique id of runner being used. + /// + public int Id => GetEnvironmentInteger("CI_RUNNER_ID"); + + /// + /// Gets the description of the runner as saved in GitLab. + /// + /// + /// The description of the runner as saved in GitLab. + /// + public string Description => GetEnvironmentString("CI_RUNNER_DESCRIPTION"); + + /// + /// Gets an array of the defined runner tags. + /// + /// + /// The defined runner tags. + /// + public string[] Tags + { + get + { + var tags = GetEnvironmentString("CI_RUNNER_TAGS").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < tags.Length; i++) + { + tags[i] = tags[i].Trim(); + } + return tags; + } + } + } +} diff --git a/src/Cake.Common/Build/GitLabCI/Data/GitLabCIServerInfo.cs b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIServerInfo.cs new file mode 100644 index 0000000000..f0e8bb3b9b --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/Data/GitLabCIServerInfo.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI.Data +{ + /// + /// Provides GitLab CI server information for a current build. + /// + public sealed class GitLabCIServerInfo : GitLabCIInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GitLabCIServerInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the name of CI server that is used to coordinate builds. + /// + /// + /// The name of CI server that is used to coordinate builds. + /// + public string Name => GetEnvironmentString("CI_SERVER_NAME"); + + /// + /// Gets the GitLab version that is used to schedule builds. + /// + /// + /// The GitLab version that is used to schedule builds. + /// + public string Version => GetEnvironmentString("CI_SERVER_VERSION"); + + /// + /// Gets the GitLab revision that is used to schedule builds. + /// + /// + /// The GitLab revision that is used to schedule builds. + /// + public string Revision => GetEnvironmentString("CI_SERVER_REVISION"); + } +} diff --git a/src/Cake.Common/Build/GitLabCI/GitLabCIInfo.cs b/src/Cake.Common/Build/GitLabCI/GitLabCIInfo.cs new file mode 100644 index 0000000000..7a2597914a --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/GitLabCIInfo.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI +{ + /// + /// Base class used to provide information about the Bitbucket Pipelines environment. + /// + public abstract class GitLabCIInfo + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + protected GitLabCIInfo(ICakeEnvironment environment) + { + _environment = environment; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected string GetEnvironmentString(string variable) + { + return _environment.GetEnvironmentVariable(variable) ?? string.Empty; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected int GetEnvironmentInteger(string variable) + { + var value = GetEnvironmentString(variable); + if (!string.IsNullOrWhiteSpace(value)) + { + int result; + if (int.TryParse(value, out result)) + { + return result; + } + } + return 0; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected bool GetEnvironmentBoolean(string variable) + { + var value = GetEnvironmentString(variable); + if (!string.IsNullOrWhiteSpace(value)) + { + return value.Equals("true", StringComparison.OrdinalIgnoreCase); + } + return false; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GitLabCI/GitLabCIProvider.cs b/src/Cake.Common/Build/GitLabCI/GitLabCIProvider.cs new file mode 100644 index 0000000000..dc496f08b3 --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/GitLabCIProvider.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Cake.Common.Build.GitLabCI.Data; +using Cake.Core; + +namespace Cake.Common.Build.GitLabCI +{ + /// + /// Responsible for communicating with GitLab CI. + /// + public class GitLabCIProvider : IGitLabCIProvider + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GitLabCIProvider(ICakeEnvironment environment) + { + if (environment == null) + { + throw new ArgumentNullException(nameof(environment)); + } + _environment = environment; + Environment = new GitLabCIEnvironmentInfo(environment); + } + + /// + /// Gets the GitLab CI environment. + /// + /// + /// The GitLab CI environment. + /// + public GitLabCIEnvironmentInfo Environment { get; } + + /// + /// Gets a value indicating whether the current build is running on GitLab CI. + /// + /// + /// true if the current build is running on GitLab CI; otherwise, false. + /// + public bool IsRunningOnGitLabCI => _environment.GetEnvironmentVariable("CI_SERVER")?.Equals("yes", StringComparison.OrdinalIgnoreCase) ?? false; + } +} diff --git a/src/Cake.Common/Build/GitLabCI/IGitLabCIProvider.cs b/src/Cake.Common/Build/GitLabCI/IGitLabCIProvider.cs new file mode 100644 index 0000000000..f70210ec93 --- /dev/null +++ b/src/Cake.Common/Build/GitLabCI/IGitLabCIProvider.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GitLabCI.Data; + +namespace Cake.Common.Build.GitLabCI +{ + /// + /// Represents a GitLab CI provider. + /// + public interface IGitLabCIProvider + { + /// + /// Gets a value indicating whether the current build is running on GitLab CI. + /// + /// + /// true if the current build is running on GitLab CI; otherwise, false. + /// + bool IsRunningOnGitLabCI { get; } + + /// + /// Gets the GitLab CI environment. + /// + /// + /// The GitLab CI environment. + /// + GitLabCIEnvironmentInfo Environment { get; } + } +} diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDBuildCauseInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDBuildCauseInfo.cs new file mode 100644 index 0000000000..73b31ca22b --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDBuildCauseInfo.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// The Go.CD build cause. + /// + [DataContract] + public class GoCDBuildCauseInfo + { + /// + /// Gets or sets the approver. + /// + /// + /// The approver. + /// + [DataMember(Name = "approver")] + public string Approver { get; set; } + + /// + /// Gets or sets the material revisions. + /// + /// + /// The material revisions. + /// + [DataMember(Name = "material_revisions")] + public IEnumerable MaterialRevisions { get; set; } + + /// + /// Gets or sets a value indicating whether the trigger was forced. + /// + /// + /// true if the trigger was forced; otherwise, false. + /// + [DataMember(Name = "trigger_forced")] + public bool TriggerForced { get; set; } + + /// + /// Gets or sets the trigger message. + /// + /// + /// The trigger message. + /// + [DataMember(Name = "trigger_message")] + public string TriggerMessage { get; set; } + } +} diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDEnvironmentInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDEnvironmentInfo.cs new file mode 100644 index 0000000000..9227d581ef --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDEnvironmentInfo.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// Provides Go.CD environment information for a current build. + /// + public sealed class GoCDEnvironmentInfo : GoCDInfo + { + /// + /// Gets GoCD pipeline information. + /// + /// + /// The GoCD pipeline information. + /// + public GoCDPipelineInfo Pipeline { get; } + + /// + /// Gets GoCD stage information. + /// + /// + /// The GoCD stage information. + /// + public GoCDStageInfo Stage { get; } + + /// + /// Gets GoCD repository information. + /// + /// + /// The GoCD repository information. + /// + public GoCDRepositoryInfo Repository { get; } + + /// + /// Gets the Go.CD URL. + /// + /// + /// The Go.CD URL. + /// + public string GoCDUrl => GetEnvironmentString("GO_SERVER_URL"); + + /// + /// Gets the environment name. This is only set if the environment is specified. Otherwise the variable is not set. + /// + /// + /// The environment name. + /// + public string EnvironmentName => GetEnvironmentString("GO_ENVIRONMENT_NAME"); + + /// + /// Gets the name of the current job being run. + /// + /// + /// The job name. + /// + public string JobName => GetEnvironmentString("GO_JOB_NAME"); + + /// + /// Gets the username of the user that triggered the build. This will have one of three possible values: + /// anonymous - if there is no security. + /// username of the user, who triggered the build. + /// changes, if SCM changes auto-triggered the build. + /// timer, if the pipeline is triggered at a scheduled time. + /// + /// + /// The username of the user that triggered the build. + /// + public string User => GetEnvironmentString("GO_TRIGGER_USER"); + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GoCDEnvironmentInfo(ICakeEnvironment environment) + : base(environment) + { + Pipeline = new GoCDPipelineInfo(environment); + Stage = new GoCDStageInfo(environment); + Repository = new GoCDRepositoryInfo(environment); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDHistoryInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDHistoryInfo.cs new file mode 100644 index 0000000000..73a123c51d --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDHistoryInfo.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// The Go.CD history. + /// + [DataContract] + public class GoCDHistoryInfo + { + /// + /// Gets or sets the pipelines. + /// + /// + /// The pipelines. + /// + [DataMember(Name = "pipelines")] + public IEnumerable Pipelines { get; set; } + } +} diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDMaterialRevisionsInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDMaterialRevisionsInfo.cs new file mode 100644 index 0000000000..b08817af5a --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDMaterialRevisionsInfo.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// The Go.CD material revision information. + /// + [DataContract] + public class GoCDMaterialRevisionsInfo + { + /// + /// Gets or sets a value indicating whether a change was made. + /// + /// + /// true if changed; otherwise, false. + /// + [DataMember(Name = "changed")] + public bool Changed { get; set; } + + /// + /// Gets or sets the modifications. + /// + /// + /// The modifications. + /// + [DataMember(Name = "modifications")] + public IEnumerable Modifications { get; set; } + } +} diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDModificationInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDModificationInfo.cs new file mode 100644 index 0000000000..83b97f41bb --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDModificationInfo.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.Serialization; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// A change made in the repository since the last time the Go.CD pipeline was run. + /// + [DataContract] + public class GoCDModificationInfo + { + /// + /// Gets or sets the email address. + /// + /// + /// The email address. + /// + [DataMember(Name = "email_address")] + public string EmailAddress { get; set; } + + /// + /// Gets or sets the identifier. + /// + /// + /// The identifier. + /// + [DataMember(Name = "id")] + public int Id { get; set; } + + /// + /// Gets or sets the modified time in milliseconds from the Unix epoch. + /// + /// + /// The modified time in milliseconds from the Unix epoch. + /// + [DataMember(Name = "modified_time")] + public long ModifiedTimeUnixMilliseconds { get; set; } + + /// + /// Gets or sets the modified time. + /// + /// + /// The modified time. + /// + public DateTime ModifiedTime + { + get { return FromUnixTimeMilliseconds(ModifiedTimeUnixMilliseconds); } + set { ModifiedTimeUnixMilliseconds = ToUnixTimeMilliseconds(value); } + } + + /// + /// Gets or sets the username. + /// + /// + /// The username. + /// + [DataMember(Name = "user_name")] + public string Username { get; set; } + + /// + /// Gets or sets the comment. + /// + /// + /// The comment. + /// + [DataMember(Name = "comment")] + public string Comment { get; set; } + + /// + /// Gets or sets the revision. + /// + /// + /// The revision. + /// + [DataMember(Name = "revision")] + public string Revision { get; set; } + + private static DateTime FromUnixTimeMilliseconds(long milliseconds) + { + if ((milliseconds < -62135596800000L) || (milliseconds > 0xe677d21fdbffL)) + { + throw new ArgumentOutOfRangeException(nameof(milliseconds)); + } + + return new DateTime((milliseconds * 0x2710L) + 0x89f7ff5f7b58000L); + } + + private static long ToUnixTimeMilliseconds(DateTime dateTime) + { + long num = dateTime.Ticks / 0x2710L; + return num - 0x3883122cd800L; + } + } +} diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDPipelineHistoryInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDPipelineHistoryInfo.cs new file mode 100644 index 0000000000..f8837b1c25 --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDPipelineHistoryInfo.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// The Go.CD pipeline history. + /// + [DataContract] + public class GoCDPipelineHistoryInfo + { + /// + /// Gets or sets the build cause. + /// + /// + /// The build cause. + /// + [DataMember(Name = "build_cause")] + public GoCDBuildCauseInfo BuildCause { get; set; } + + /// + /// Gets or sets the comment. + /// + /// + /// The comment. + /// + [DataMember(Name = "comment")] + public string Comment { get; set; } + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + [DataMember(Name = "name")] + public string Name { get; set; } + + /// + /// Gets or sets the natural order. + /// + /// + /// The natural order. + /// + [DataMember(Name = "natural_order")] + public string NaturalOrder { get; set; } + } +} diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDPipelineInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDPipelineInfo.cs new file mode 100644 index 0000000000..11218db469 --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDPipelineInfo.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// Provides GoCD pipeline information for a current build. + /// + public sealed class GoCDPipelineInfo : GoCDInfo + { + /// + /// Gets the name of the pipeline. + /// + /// + /// The name of the pipeline. + /// + public string Name => GetEnvironmentString("GO_PIPELINE_NAME"); + + /// + /// Gets the pipeline counter, showing how many times the current pipeline has been run. + /// + /// + /// The pipeline counter. + /// + public int Counter => GetEnvironmentInteger("GO_PIPELINE_COUNTER"); + + /// + /// Gets the pipeline label. By default, this is set to the pipeline count. + /// + /// + /// The pipeline label. + /// + public string Label => GetEnvironmentString("GO_PIPELINE_LABEL"); + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GoCDPipelineInfo(ICakeEnvironment environment) + : base(environment) + { + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDRepositoryInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDRepositoryInfo.cs new file mode 100644 index 0000000000..aff82b63b6 --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDRepositoryInfo.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// Provides Go.CD repository information for a current build. + /// + public sealed class GoCDRepositoryInfo : GoCDInfo + { + /// + /// Gets the source control revision. + /// + /// + /// The the source control revision. + /// + public string Revision => GetEnvironmentString("GO_REVISION"); + + /// + /// Gets the last revision the build was triggered by if there were multiple revisions. + /// + /// + /// The last revision the build was triggered by if there were multiple revisions. + /// + public string ToRevision => GetEnvironmentString("GO_TO_REVISION"); + + /// + /// Gets the first revision the build was triggered by if there were multiple revisions. + /// + /// + /// The first revision the build was triggered by if there were multiple revisions. + /// + public string FromRevision => GetEnvironmentString("GO_FROM_REVISION"); + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GoCDRepositoryInfo(ICakeEnvironment environment) + : base(environment) + { + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GoCD/Data/GoCDStageInfo.cs b/src/Cake.Common/Build/GoCD/Data/GoCDStageInfo.cs new file mode 100644 index 0000000000..2be00b2eb1 --- /dev/null +++ b/src/Cake.Common/Build/GoCD/Data/GoCDStageInfo.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.GoCD.Data +{ + /// + /// Provides Go.CD commit information for a current build. + /// + public sealed class GoCDStageInfo : GoCDInfo + { + /// + /// Gets the name of the current stage being run. + /// + /// + /// The stage name. + /// + public string Name => GetEnvironmentString("GO_STAGE_NAME"); + + /// + /// Gets the count of the number of times the current stage has been run. + /// + /// + /// The stage counter. + /// + public int Counter => GetEnvironmentInteger("GO_STAGE_COUNTER"); + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public GoCDStageInfo(ICakeEnvironment environment) + : base(environment) + { + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GoCD/GoCDInfo.cs b/src/Cake.Common/Build/GoCD/GoCDInfo.cs new file mode 100644 index 0000000000..78239826be --- /dev/null +++ b/src/Cake.Common/Build/GoCD/GoCDInfo.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; + +namespace Cake.Common.Build.GoCD +{ + /// + /// Base class used to provide information about the Go.CD environment. + /// + public abstract class GoCDInfo + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + protected GoCDInfo(ICakeEnvironment environment) + { + _environment = environment; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected string GetEnvironmentString(string variable) + { + return _environment.GetEnvironmentVariable(variable) ?? string.Empty; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected int GetEnvironmentInteger(string variable) + { + var value = GetEnvironmentString(variable); + if (!string.IsNullOrWhiteSpace(value)) + { + int result; + if (int.TryParse(value, out result)) + { + return result; + } + } + return 0; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected bool GetEnvironmentBoolean(string variable) + { + var value = GetEnvironmentString(variable); + if (!string.IsNullOrWhiteSpace(value)) + { + return value.Equals("true", StringComparison.OrdinalIgnoreCase); + } + return false; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GoCD/GoCDProvider.cs b/src/Cake.Common/Build/GoCD/GoCDProvider.cs new file mode 100644 index 0000000000..7f657ef5d0 --- /dev/null +++ b/src/Cake.Common/Build/GoCD/GoCDProvider.cs @@ -0,0 +1,117 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.IO; +using System.Net.Http; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Threading.Tasks; +using Cake.Common.Build.GoCD.Data; +using Cake.Core; +using Cake.Core.Diagnostics; + +namespace Cake.Common.Build.GoCD +{ + /// + /// Responsible for communicating with GoCD. + /// + public sealed class GoCDProvider : IGoCDProvider + { + private readonly ICakeLog _cakeLog; + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + /// The cake log. + public GoCDProvider(ICakeEnvironment environment, ICakeLog cakeLog) + { + if (environment == null) + { + throw new ArgumentNullException(nameof(environment)); + } + + if (cakeLog == null) + { + throw new ArgumentNullException(nameof(cakeLog)); + } + + _environment = environment; + _cakeLog = cakeLog; + Environment = new GoCDEnvironmentInfo(environment); + } + + /// + /// Gets a value indicating whether the current build is running on Go.CD. + /// + /// + /// true if the current build is running on Go.CD.; otherwise, false. + /// + public bool IsRunningOnGoCD => !string.IsNullOrWhiteSpace(_environment.GetEnvironmentVariable("GO_SERVER_URL")); + + /// + /// Gets the Go.CD environment. + /// + /// + /// The Go.CD environment. + /// + public GoCDEnvironmentInfo Environment { get; } + + /// + /// Gets the Go.CD build history, including the repository modifications that caused the pipeline to start. + /// + /// The Go.CD username. + /// The Go.CD password. + /// The Go.CD build history. + public GoCDHistoryInfo GetHistory(string username, string password) + { + if (username == null) + { + throw new ArgumentNullException(nameof(username)); + } + + if (password == null) + { + throw new ArgumentNullException(nameof(password)); + } + + if (!IsRunningOnGoCD) + { + throw new CakeException("The current build is not running on Go.CD."); + } + + var url = new Uri(string.Format( + CultureInfo.InvariantCulture, + "{0}/go/api/pipelines/{1}/history/0", + this.Environment.GoCDUrl, + this.Environment.Pipeline.Name).ToLowerInvariant()); + + _cakeLog.Write(Verbosity.Diagnostic, LogLevel.Verbose, "Getting [{0}]", url); + return Task.Run(async () => + { + var encodedCredentials = Convert.ToBase64String(Encoding.ASCII.GetBytes( + string.Format(CultureInfo.InvariantCulture, "{0}:{1}", username, password))); + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.Add( + "Authorization", + string.Format(CultureInfo.InvariantCulture, "Basic {0}", encodedCredentials)); + var response = await client.GetAsync(url); + var content = await response.Content.ReadAsStringAsync(); + _cakeLog.Write(Verbosity.Diagnostic, LogLevel.Verbose, "Server response [{0}:{1}]:\n\r{2}", response.StatusCode, response.ReasonPhrase, content); + + var jsonSerializer = new DataContractJsonSerializer(typeof(GoCDHistoryInfo)); + + using (var jsonStream = new MemoryStream(Encoding.UTF8.GetBytes(content))) + { + return jsonSerializer.ReadObject(jsonStream) as GoCDHistoryInfo; + } + } + }).GetAwaiter().GetResult(); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/GoCD/IGoCDProvider.cs b/src/Cake.Common/Build/GoCD/IGoCDProvider.cs new file mode 100644 index 0000000000..bb1a9acbad --- /dev/null +++ b/src/Cake.Common/Build/GoCD/IGoCDProvider.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.GoCD.Data; + +namespace Cake.Common.Build.GoCD +{ + /// + /// Represents a Go.CD provider. + /// + public interface IGoCDProvider + { + /// + /// Gets a value indicating whether the current build is running on Go.CD. + /// + /// + /// true if the current build is running on Go.CD; otherwise, false. + /// + bool IsRunningOnGoCD { get; } + + /// + /// Gets the Go.CD environment. + /// + /// + /// The Go.CD environment. + /// + GoCDEnvironmentInfo Environment { get; } + + /// + /// Gets the Go.CD build history, including the repository modifications that caused the pipeline to start. + /// + /// The Go.CD username. + /// The Go.CD password. + /// The Go.CD build history. + GoCDHistoryInfo GetHistory(string username, string password); + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/TFBuild/Data/TFBuildAgentInfo.cs b/src/Cake.Common/Build/TFBuild/Data/TFBuildAgentInfo.cs new file mode 100644 index 0000000000..37cae885f9 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFBuildAgentInfo.cs @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; +using Cake.Core.IO; + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides TF Build agent info for the current build and build agent + /// + public sealed class TFBuildAgentInfo : TFInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildAgentInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the local path on the agent where all folders for a given build definition are created. + /// + /// + /// The local path on the agent where all folders for a given build definition are created. + /// + /// c:\agent\_work\1 + public FilePath BuildDirectory => GetEnvironmentString("AGENT_BUILDDIRECTORY"); + + /// + /// Gets the directory the agent is installed into. This contains the agent software. + /// + /// If you are using an on-premises agent, this directory is specified by you. + /// + /// The directory the agent is installed into. + /// + /// c:\agent\ + public FilePath HomeDirectory => GetEnvironmentString("AGENT_HOMEDIRECTORY"); + + /// + /// Gets the working directory for this agent. + /// + /// + /// The working directory for this agent. + /// + public FilePath WorkingDirectory => GetEnvironmentString("AGENT_WORKFOLDER"); + + /// + /// Gets the ID of the agent. + /// + /// + /// The ID of the agent. + /// + public int Id => GetEnvironmentInteger("AGENT_ID"); + + /// + /// Gets the name of the agent that is registered with the pool. + /// + /// If you are using an on-premises agent, this is specified by you. + /// + /// The name of the agent that is registered with the pool. + /// + public string Name => GetEnvironmentString("AGENT_NAME"); + + /// + /// Gets the name of the machine on which the agent is installed. + /// + /// + /// The name of the machine on which the agent is installed. + /// + public string MachineName => GetEnvironmentString("AGENT_MACHINE_NAME"); + + /// + /// Gets a value indicating whether the current agent is a hosted agent. + /// + /// + /// true if the current agent is a hosted agent; otherwise, false. + /// + public bool IsHosted => Name == "Hosted Agent"; + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/TFBuild/Data/TFBuildDefinitionInfo.cs b/src/Cake.Common/Build/TFBuild/Data/TFBuildDefinitionInfo.cs new file mode 100644 index 0000000000..60adff62c1 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFBuildDefinitionInfo.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides TF Build Definition information for the current build + /// + public sealed class TFBuildDefinitionInfo : TFInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildDefinitionInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the build definition ID. + /// + /// + /// The build definition ID. + /// + public int Id => GetEnvironmentInteger("SYSTEM_DEFINITIONID"); + + /// + /// Gets the build definition name. + /// + /// + /// The build definition name. + /// + public string Name => GetEnvironmentString("BUILD_DEFINITIONNAME"); + + /// + /// Gets the build definition version. + /// + /// + /// The build definition version. + /// + public int Version => GetEnvironmentInteger("BUILD_DEFINITIONVERSION"); + } +} diff --git a/src/Cake.Common/Build/TFBuild/Data/TFBuildEnvironmentInfo.cs b/src/Cake.Common/Build/TFBuild/Data/TFBuildEnvironmentInfo.cs new file mode 100644 index 0000000000..786671ba4d --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFBuildEnvironmentInfo.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides TF Build Environment information for the current build. + /// + public sealed class TFBuildEnvironmentInfo : TFInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildEnvironmentInfo(ICakeEnvironment environment) + : base(environment) + { + Repository = new TFBuildRepositoryInfo(environment); + BuildDefinition = new TFBuildDefinitionInfo(environment); + Build = new TFBuildInfo(environment); + Agent = new TFBuildAgentInfo(environment); + TeamProject = new TFBuildTeamProjectInfo(environment); + } + + /// + /// Gets TF Build repository information + /// + /// + /// The TF Build repository information. + /// + public TFBuildRepositoryInfo Repository { get; } + + /// + /// Gets TF Build Definition information. + /// + /// + /// The TF Build Definition. + /// + public TFBuildDefinitionInfo BuildDefinition { get; } + + /// + /// Gets TF Build information. + /// + /// + /// The TF Build. + /// + public TFBuildInfo Build { get; } + + /// + /// Gets TF Team Project information. + /// + /// + /// The TF Team Project. + /// + public TFBuildTeamProjectInfo TeamProject { get; } + + /// + /// Gets TF Build agent information. + /// + /// + /// The TF Build agent. + /// + public TFBuildAgentInfo Agent { get; } + } +} diff --git a/src/Cake.Common/Build/TFBuild/Data/TFBuildInfo.cs b/src/Cake.Common/Build/TFBuild/Data/TFBuildInfo.cs new file mode 100644 index 0000000000..c9a27b56f7 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFBuildInfo.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides TF Build info for the current build. + /// + public sealed class TFBuildInfo : TFInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the ID of the record for the completed build. + /// + /// + /// The ID of the record for the completed build. + /// + public int Id => GetEnvironmentInteger("BUILD_BUILDID"); + + /// + /// Gets the name of the completed build. + /// + /// You can specify the build number format that generates this value in the build definition. + /// + /// The name of the completed build. + /// + public string Number => GetEnvironmentString("BUILD_BUILDNUMBER"); + + /// + /// Gets the URI for the build. + /// + /// vstfs:///Build/Build/1430 + /// + /// The URI for the build. + /// + public Uri Uri => new Uri(GetEnvironmentString("BUILD_BUILDURI")); + + /// + /// Gets the user who queued the build. + /// + /// + /// The user who queued the build. + /// + public string QueuedBy => GetEnvironmentString("BUILD_QUEUEDBY"); + + /// + /// Gets the user the build was requested for. + /// + /// + /// The user the build was requested for. + /// + public string RequestedFor => GetEnvironmentString("BUILD_REQUESTEDFOR"); + + /// + /// Gets the email of the user the build was requested for. + /// + /// + /// The email of the user the build was requested for. + /// + public string RequestedForEmail => GetEnvironmentString("BUILD_REQUESTEDFOREMAIL"); + } +} diff --git a/src/Cake.Common/Build/TFBuild/Data/TFBuildRepositoryInfo.cs b/src/Cake.Common/Build/TFBuild/Data/TFBuildRepositoryInfo.cs new file mode 100644 index 0000000000..b102999b0b --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFBuildRepositoryInfo.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Core; + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides TF Build Repository information for the current build + /// + public sealed class TFBuildRepositoryInfo : TFInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildRepositoryInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets name of the branch the build was queued for. + /// + /// + /// The SCM branch + /// + public string Branch => GetEnvironmentString("BUILD_SOURCEBRANCHNAME"); + + /// + /// Gets the latest version control change that is included in this build. + /// + /// Note: for Git this is the commit ID. For TFVC this is the changeset. + /// + /// The SCM source version + /// + public string SourceVersion => GetEnvironmentString("BUILD_SOURCEVERSION"); + + /// + /// Gets the name of the shelveset you are building, if you are running a gated build or a shelveset build. + /// + /// Defined only if your repository is Team Foundation Version Control. + /// + /// The shelveset name + /// + public string Shelveset => GetEnvironmentString("BUILD_SOURCETFVCSHELVESET"); + + /// + /// Gets the name of the repository + /// + /// + /// The name of the repository + /// + public string RepoName => GetEnvironmentString("BUILD_REPOSITORY_NAME"); + + /// + /// Gets the type of the current repository. + /// + /// + /// The type of the current repository. + /// + public TFRepositoryType? Provider => GetRepositoryType("BUILD_REPOSITORY_PROVIDER"); + } +} \ No newline at end of file diff --git a/src/Cake.Common/Build/TFBuild/Data/TFBuildTeamProjectInfo.cs b/src/Cake.Common/Build/TFBuild/Data/TFBuildTeamProjectInfo.cs new file mode 100644 index 0000000000..8811d40e30 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFBuildTeamProjectInfo.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides Team Foundation Team Project information for the current build + /// + public sealed class TFBuildTeamProjectInfo : TFInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildTeamProjectInfo(ICakeEnvironment environment) : base(environment) + { + } + + /// + /// Gets the name of the team project that contains this build. + /// + /// + /// The name of the team project that contains this build. + /// + public string Name => GetEnvironmentString("SYSTEM_TEAMPROJECT"); + + /// + /// Gets the ID of the team project that contains this build. + /// + /// + /// The ID of the team project that contains this build. + /// + public string Id => GetEnvironmentString("SYSTEM_TEAMPROJECTID"); + + /// + /// Gets the URI of the team foundation collection. + /// + /// + /// The URI of the team foundation collection. + /// + public Uri CollectionUri => GetEnvironmentUri("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"); + } +} diff --git a/src/Cake.Common/Build/TFBuild/Data/TFRepositoryType.cs b/src/Cake.Common/Build/TFBuild/Data/TFRepositoryType.cs new file mode 100644 index 0000000000..9f486a1ac7 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/Data/TFRepositoryType.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Cake.Common.Build.TFBuild.Data +{ + /// + /// Provides the known values for the TF Build Repository types. + /// + public enum TFRepositoryType + { + /// + /// TFS Git repository. + /// + TfsGit, + + /// + /// Team Foundation Version Control repository. + /// + TfsVersionControl, + + /// + /// Git repository hosted on an external server. + /// + Git, + + /// + /// GitHub repository. + /// + GitHub, + + /// + /// Subversion repository. + /// + Svn + } +} diff --git a/src/Cake.Common/Build/TFBuild/ITFBuildProvider.cs b/src/Cake.Common/Build/TFBuild/ITFBuildProvider.cs new file mode 100644 index 0000000000..43a17ea1e8 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/ITFBuildProvider.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Build.TFBuild.Data; + +namespace Cake.Common.Build.TFBuild +{ + /// + /// Represents a TF Build provider. + /// + public interface ITFBuildProvider + { + /// + /// Gets a value indicating whether the current build is running on VSTS. + /// + /// + /// true if the current build is running on VSTS; otherwise, false. + /// + bool IsRunningOnVSTS { get; } + + /// + /// Gets a value indicating whether the current build is running on TFS. + /// + /// + /// true if the current build is running on TFS; otherwise, false. + /// + bool IsRunningOnTFS { get; } + + /// + /// Gets the TF Build environment. + /// + /// + /// The TF Build environment. + /// + TFBuildEnvironmentInfo Environment { get; } + } +} diff --git a/src/Cake.Common/Build/TFBuild/TFBuildProvider.cs b/src/Cake.Common/Build/TFBuild/TFBuildProvider.cs new file mode 100644 index 0000000000..79080f3313 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/TFBuildProvider.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Common.Build.TFBuild.Data; +using Cake.Core; + +namespace Cake.Common.Build.TFBuild +{ + /// + /// Responsible for communicating with Team Foundation Build (VSTS or TFS). + /// + public sealed class TFBuildProvider : ITFBuildProvider + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public TFBuildProvider(ICakeEnvironment environment) + { + if (environment == null) + { + throw new ArgumentNullException(nameof(environment)); + } + _environment = environment; + Environment = new TFBuildEnvironmentInfo(environment); + } + + /// + /// Gets a value indicating whether the current build is running on VSTS. + /// + /// + /// true if the current build is running on VSTS; otherwise, false. + /// + public bool IsRunningOnVSTS + => !string.IsNullOrWhiteSpace(_environment.GetEnvironmentVariable("TF_BUILD")) && IsHostedAgent; + + /// + /// Gets a value indicating whether the current build is running on TFS. + /// + /// + /// true if the current build is running on TFS; otherwise, false. + /// + public bool IsRunningOnTFS + => !string.IsNullOrWhiteSpace(_environment.GetEnvironmentVariable("TF_BUILD")) && !IsHostedAgent; + + /// + /// Gets the TF Build environment. + /// + /// + /// The TF Build environment. + /// + public TFBuildEnvironmentInfo Environment { get; } + + /// + /// Gets a value indicating whether the current build is running on a hosted build agent. + /// + /// + /// true if the current build is running on a hosted agent; otherwise, false. + /// + private bool IsHostedAgent + => + !string.IsNullOrWhiteSpace(_environment.GetEnvironmentVariable("AGENT_NAME")) && + _environment.GetEnvironmentVariable("AGENT_NAME") == "Hosted Agent"; + } +} diff --git a/src/Cake.Common/Build/TFBuild/TFInfo.cs b/src/Cake.Common/Build/TFBuild/TFInfo.cs new file mode 100644 index 0000000000..36732c17a5 --- /dev/null +++ b/src/Cake.Common/Build/TFBuild/TFInfo.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Common.Build.TFBuild.Data; +using Cake.Core; + +namespace Cake.Common.Build.TFBuild +{ + /// + /// Base class used to provide information about the TF Build environment. + /// + public abstract class TFInfo + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + protected TFInfo(ICakeEnvironment environment) + { + _environment = environment; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected string GetEnvironmentString(string variable) + { + return _environment.GetEnvironmentVariable(variable) ?? string.Empty; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected int GetEnvironmentInteger(string variable) + { + var value = GetEnvironmentString(variable); + if (!string.IsNullOrWhiteSpace(value)) + { + int result; + if (int.TryParse(value, out result)) + { + return result; + } + } + return 0; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected bool GetEnvironmentBoolean(string variable) + { + var value = GetEnvironmentString(variable); + if (!string.IsNullOrWhiteSpace(value)) + { + return value.Equals("true", StringComparison.OrdinalIgnoreCase); + } + return false; + } + + /// + /// Gets an environment variable as a . + /// + /// The environment variable name. + /// The environment variable. + protected Uri GetEnvironmentUri(string variable) + { + var value = GetEnvironmentString(variable); + Uri uri; + if (Uri.TryCreate(value, UriKind.Absolute, out uri)) + { + return uri; + } + return null; + } + + /// + /// Gets the current repository type as a from an environment variable. + /// + /// The environment variable name. + /// The current repository type. + protected TFRepositoryType? GetRepositoryType(string variable) + { + var value = GetEnvironmentString(variable); + TFRepositoryType type; + if (Enum.TryParse(value, true, out type)) + { + return type; + } + return null; + } + } +} diff --git a/src/Cake.Common/EnviromentAliases.cs b/src/Cake.Common/EnviromentAliases.cs index e6df846291..20c1328fe6 100644 --- a/src/Cake.Common/EnviromentAliases.cs +++ b/src/Cake.Common/EnviromentAliases.cs @@ -16,7 +16,7 @@ namespace Cake.Common public static class EnvironmentAliases { /// - /// Retrieves the value of the environment variable or null if the environment variable do not exist. + /// Retrieves the value of the environment variable or null if the environment variable does not exist. /// /// /// @@ -25,7 +25,7 @@ public static class EnvironmentAliases /// /// The context. /// The environment variable. - /// The environment variable or null if the environment variable do not exist. + /// The environment variable or null if the environment variable does not exist. [CakeMethodAlias] [CakeAliasCategory("Environment Variables")] public static string EnvironmentVariable(this ICakeContext context, string variable) diff --git a/src/Cake.Common/IO/DirectoryAliases.cs b/src/Cake.Common/IO/DirectoryAliases.cs index 8f7fa95608..57efdefac7 100644 --- a/src/Cake.Common/IO/DirectoryAliases.cs +++ b/src/Cake.Common/IO/DirectoryAliases.cs @@ -131,7 +131,7 @@ public static void DeleteDirectory(this ICakeContext context, DirectoryPath path /// /// Cleans the directories matching the specified pattern. - /// Cleaning the directory will remove all it's content but not the directory itself. + /// Cleaning the directory will remove all its content but not the directory itself. /// /// /// @@ -155,7 +155,7 @@ public static void CleanDirectories(this ICakeContext context, string pattern) /// /// Cleans the directories matching the specified pattern. - /// Cleaning the directory will remove all it's content but not the directory itself. + /// Cleaning the directory will remove all its content but not the directory itself. /// /// /// @@ -184,7 +184,7 @@ public static void CleanDirectories(this ICakeContext context, string pattern, F /// /// Cleans the specified directories. - /// Cleaning a directory will remove all it's content but not the directory itself. + /// Cleaning a directory will remove all its content but not the directory itself. /// /// /// @@ -210,7 +210,7 @@ public static void CleanDirectories(this ICakeContext context, IEnumerable /// Cleans the specified directories. - /// Cleaning a directory will remove all it's content but not the directory itself. + /// Cleaning a directory will remove all its content but not the directory itself. /// /// /// @@ -439,5 +439,23 @@ public static DirectoryPath MakeAbsolute(this ICakeContext context, DirectoryPat return path.MakeAbsolute(context.Environment); } + + /// + /// Moves an existing directory to a new location, providing the option to specify a new directory name. + /// + /// The context. + /// The directory path. + /// The target directory path. + /// + /// + /// MoveDirectory("mydir", "newparent/newdir"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Move")] + public static void MoveDirectory(this ICakeContext context, DirectoryPath directoryPath, DirectoryPath targetDirectoryPath) + { + DirectoryMover.MoveDirectory(context, directoryPath, targetDirectoryPath); + } } } \ No newline at end of file diff --git a/src/Cake.Common/IO/DirectoryDeleter.cs b/src/Cake.Common/IO/DirectoryDeleter.cs index 9040c6fb14..e8cd88732a 100644 --- a/src/Cake.Common/IO/DirectoryDeleter.cs +++ b/src/Cake.Common/IO/DirectoryDeleter.cs @@ -33,7 +33,7 @@ public static void Delete(ICakeContext context, DirectoryPath path, bool recursi var directory = context.FileSystem.GetDirectory(path); if (!directory.Exists) { - const string format = "The directory '{0}' do not exist."; + const string format = "The directory '{0}' does not exist."; throw new IOException(string.Format(CultureInfo.InvariantCulture, format, path.FullPath)); } diff --git a/src/Cake.Common/IO/DirectoryMover.cs b/src/Cake.Common/IO/DirectoryMover.cs new file mode 100644 index 0000000000..8190fd8dd0 --- /dev/null +++ b/src/Cake.Common/IO/DirectoryMover.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using Cake.Core; +using Cake.Core.Diagnostics; +using Cake.Core.IO; + +namespace Cake.Common.IO +{ + internal static class DirectoryMover + { + public static void MoveDirectory(ICakeContext context, DirectoryPath directoryPath, DirectoryPath targetDirectoryPath) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (directoryPath == null) + { + throw new ArgumentNullException(nameof(directoryPath)); + } + if (targetDirectoryPath == null) + { + throw new ArgumentNullException(nameof(targetDirectoryPath)); + } + + directoryPath = directoryPath.MakeAbsolute(context.Environment); + targetDirectoryPath = targetDirectoryPath.MakeAbsolute(context.Environment); + + // Get the directory and verify it exist. + var directory = context.FileSystem.GetDirectory(directoryPath); + if (!directory.Exists) + { + const string format = "The directory '{0}' does not exist."; + var message = string.Format(CultureInfo.InvariantCulture, format, directoryPath.FullPath); + throw new DirectoryNotFoundException(message); + } + + // Move the directory. + context.Log.Verbose("Moving directory {0} to {1}", directoryPath.GetDirectoryName(), targetDirectoryPath); + directory.Move(targetDirectoryPath); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/IO/FileAliases.cs b/src/Cake.Common/IO/FileAliases.cs index b5c285f88f..bc74f89727 100644 --- a/src/Cake.Common/IO/FileAliases.cs +++ b/src/Cake.Common/IO/FileAliases.cs @@ -101,7 +101,7 @@ public static void CopyFile(this ICakeContext context, FilePath filePath, FilePa [CakeAliasCategory("Copy")] public static void CopyFiles(this ICakeContext context, string pattern, DirectoryPath targetDirectoryPath) { - FileCopier.CopyFiles(context, pattern, targetDirectoryPath); + FileCopier.CopyFiles(context, pattern, targetDirectoryPath, false); } /// @@ -120,7 +120,7 @@ public static void CopyFiles(this ICakeContext context, string pattern, Director [CakeAliasCategory("Copy")] public static void CopyFiles(this ICakeContext context, IEnumerable filePaths, DirectoryPath targetDirectoryPath) { - FileCopier.CopyFiles(context, filePaths, targetDirectoryPath); + FileCopier.CopyFiles(context, filePaths, targetDirectoryPath, false); } /// @@ -148,7 +148,75 @@ public static void CopyFiles(this ICakeContext context, IEnumerable file throw new ArgumentNullException(nameof(filePaths)); } var paths = filePaths.Select(p => new FilePath(p)); - FileCopier.CopyFiles(context, paths, targetDirectoryPath); + FileCopier.CopyFiles(context, paths, targetDirectoryPath, false); + } + + /// + /// Copies all files matching the provided pattern to a new location. + /// + /// The context. + /// The pattern. + /// The target directory path. + /// Keep the folder structure. + /// + /// + /// CopyFiles("Cake.*", "./publish"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Copy")] + public static void CopyFiles(this ICakeContext context, string pattern, DirectoryPath targetDirectoryPath, bool preserveFolderStructure) + { + FileCopier.CopyFiles(context, pattern, targetDirectoryPath, preserveFolderStructure); + } + + /// + /// Copies existing files to a new location. + /// + /// The context. + /// The file paths. + /// The target directory path. + /// Keep the folder structure. + /// + /// + /// var files = GetFiles("./**/Cake.*"); + /// CopyFiles(files, "destination"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Copy")] + public static void CopyFiles(this ICakeContext context, IEnumerable filePaths, DirectoryPath targetDirectoryPath, bool preserveFolderStructure) + { + FileCopier.CopyFiles(context, filePaths, targetDirectoryPath, preserveFolderStructure); + } + + /// + /// Copies existing files to a new location. + /// + /// The context. + /// The file paths. + /// The target directory path. + /// Keep the folder structure. + /// + /// + /// CreateDirectory("destination"); + /// var files = new [] { + /// "Cake.exe", + /// "Cake.pdb" + /// }; + /// CopyFiles(files, "destination"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Copy")] + public static void CopyFiles(this ICakeContext context, IEnumerable filePaths, DirectoryPath targetDirectoryPath, bool preserveFolderStructure) + { + if (filePaths == null) + { + throw new ArgumentNullException(nameof(filePaths)); + } + var paths = filePaths.Select(p => new FilePath(p)); + FileCopier.CopyFiles(context, paths, targetDirectoryPath, preserveFolderStructure); } /// diff --git a/src/Cake.Common/IO/FileCopier.cs b/src/Cake.Common/IO/FileCopier.cs index 767d222141..94550672b3 100644 --- a/src/Cake.Common/IO/FileCopier.cs +++ b/src/Cake.Common/IO/FileCopier.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using Cake.Core; using Cake.Core.Diagnostics; using Cake.Core.IO; @@ -51,46 +52,47 @@ public static void CopyFile(ICakeContext context, FilePath filePath, FilePath ta // Make sure the target directory exist. if (!context.FileSystem.Exist(targetDirectoryPath)) { - const string format = "The directory '{0}' do not exist."; + const string format = "The directory '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, targetDirectoryPath.FullPath); throw new DirectoryNotFoundException(message); } - CopyFileCore(context, filePath, targetFilePath); + CopyFileCore(context, filePath, targetFilePath, null); } - public static void CopyFiles(ICakeContext context, string pattern, DirectoryPath targetDirectoryPath) + public static void CopyFiles(ICakeContext context, string pattern, DirectoryPath targetDirectoryPath, bool preserverFolderStructure) { if (context == null) { - throw new ArgumentNullException(nameof(context)); + throw new ArgumentNullException("context"); } if (pattern == null) { - throw new ArgumentNullException(nameof(pattern)); + throw new ArgumentNullException("pattern"); } var files = context.GetFiles(pattern); + if (files.Count == 0) { context.Log.Verbose("The provided pattern did not match any files."); return; } - CopyFiles(context, files, targetDirectoryPath); + CopyFiles(context, files, targetDirectoryPath, preserverFolderStructure); } - public static void CopyFiles(ICakeContext context, IEnumerable filePaths, DirectoryPath targetDirectoryPath) + public static void CopyFiles(ICakeContext context, IEnumerable filePaths, DirectoryPath targetDirectoryPath, bool preserverFolderStructure) { if (context == null) { - throw new ArgumentNullException(nameof(context)); + throw new ArgumentNullException("context"); } if (filePaths == null) { - throw new ArgumentNullException(nameof(filePaths)); + throw new ArgumentNullException("filePaths"); } if (targetDirectoryPath == null) { - throw new ArgumentNullException(nameof(targetDirectoryPath)); + throw new ArgumentNullException("targetDirectoryPath"); } var absoluteTargetDirectoryPath = targetDirectoryPath.MakeAbsolute(context.Environment); @@ -98,35 +100,87 @@ public static void CopyFiles(ICakeContext context, IEnumerable filePat // Make sure the target directory exist. if (!context.FileSystem.Exist(absoluteTargetDirectoryPath)) { - const string format = "The directory '{0}' do not exist."; + const string format = "The directory '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, absoluteTargetDirectoryPath.FullPath); throw new DirectoryNotFoundException(message); } - // Iterate all files and copy them. - foreach (var filePath in filePaths) + if (preserverFolderStructure) + { + var commonPath = string.Empty; + List separatedPath = filePaths + .First(str => str.ToString().Length == filePaths.Max(st2 => st2.ToString().Length)).ToString() + .Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries) + .ToList(); + + foreach (string pathSegment in separatedPath) + { + if (commonPath.Length == 0 && filePaths.All(str => str.ToString().StartsWith(pathSegment))) + { + commonPath = pathSegment; + } + else if (filePaths.All(str => str.ToString().StartsWith(commonPath + "/" + pathSegment))) + { + commonPath += "/" + pathSegment; + } + else + { + break; + } + } + + // Iterate all files and copy them. + foreach (var filePath in filePaths) + { + CopyFileCore(context, filePath, absoluteTargetDirectoryPath.GetFilePath(filePath), context.DirectoryExists(commonPath) ? commonPath : null); + } + } + else { - CopyFileCore(context, filePath, absoluteTargetDirectoryPath.GetFilePath(filePath)); + // Iterate all files and copy them. + foreach (var filePath in filePaths) + { + CopyFileCore(context, filePath, absoluteTargetDirectoryPath.GetFilePath(filePath), null); + } } } - private static void CopyFileCore(ICakeContext context, FilePath filePath, FilePath targetFilePath) + private static void CopyFileCore(ICakeContext context, FilePath filePath, FilePath targetFilePath, string commonPath) { var absoluteFilePath = filePath.MakeAbsolute(context.Environment); // Get the file. if (!context.FileSystem.Exist(absoluteFilePath)) { - const string format = "The file '{0}' do not exist."; + const string format = "The file '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, absoluteFilePath.FullPath); throw new FileNotFoundException(message, absoluteFilePath.FullPath); } // Copy the file. var absoluteTargetPath = targetFilePath.MakeAbsolute(context.Environment); - context.Log.Verbose("Copying file {0} to {1}", absoluteFilePath.GetFilename(), absoluteTargetPath); var file = context.FileSystem.GetFile(absoluteFilePath); - file.Copy(absoluteTargetPath, true); + + if (!string.IsNullOrEmpty(commonPath)) + { + // Get the parent folder structure and create it. + var newRelativeFolderPath = context.Directory(commonPath).Path.GetRelativePath(filePath.GetDirectory()); + var newTargetPath = targetFilePath.GetDirectory().Combine(newRelativeFolderPath); + var newAbsoluteTargetPath = newTargetPath.CombineWithFilePath(filePath.GetFilename()); + context.Log.Verbose("Copying file {0} to {1}", absoluteFilePath.GetFilename(), newAbsoluteTargetPath); + + if (!context.DirectoryExists(newTargetPath)) + { + context.CreateDirectory(newTargetPath); + } + + file.Copy(newAbsoluteTargetPath, true); + } + else + { + context.Log.Verbose("Copying file {0} to {1}", absoluteFilePath.GetFilename(), absoluteTargetPath); + file.Copy(absoluteTargetPath, true); + } } } -} \ No newline at end of file +} diff --git a/src/Cake.Common/IO/FileDeleter.cs b/src/Cake.Common/IO/FileDeleter.cs index 780281e817..252e3f80b4 100644 --- a/src/Cake.Common/IO/FileDeleter.cs +++ b/src/Cake.Common/IO/FileDeleter.cs @@ -68,7 +68,7 @@ public static void DeleteFile(ICakeContext context, FilePath filePath) var file = context.FileSystem.GetFile(filePath); if (!file.Exists) { - const string format = "The file '{0}' do not exist."; + const string format = "The file '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, filePath.FullPath); throw new FileNotFoundException(message, filePath.FullPath); } diff --git a/src/Cake.Common/IO/FileMover.cs b/src/Cake.Common/IO/FileMover.cs index df76d26a3a..1e7dde1cf0 100644 --- a/src/Cake.Common/IO/FileMover.cs +++ b/src/Cake.Common/IO/FileMover.cs @@ -72,7 +72,7 @@ public static void MoveFiles(this ICakeContext context, IEnumerable fi // Make sure the target directory exist. if (!context.FileSystem.Exist(targetDirectoryPath)) { - const string format = "The directory '{0}' do not exist."; + const string format = "The directory '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, targetDirectoryPath.FullPath); throw new DirectoryNotFoundException(message); } @@ -106,7 +106,7 @@ public static void MoveFile(ICakeContext context, FilePath filePath, FilePath ta var targetDirectoryPath = targetFilePath.GetDirectory().MakeAbsolute(context.Environment); if (!context.FileSystem.Exist(targetDirectoryPath)) { - const string format = "The directory '{0}' do not exist."; + const string format = "The directory '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, targetDirectoryPath.FullPath); throw new DirectoryNotFoundException(message); } @@ -115,7 +115,7 @@ public static void MoveFile(ICakeContext context, FilePath filePath, FilePath ta var file = context.FileSystem.GetFile(filePath); if (!file.Exists) { - const string format = "The file '{0}' do not exist."; + const string format = "The file '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, filePath.FullPath); throw new FileNotFoundException(message, filePath.FullPath); } diff --git a/src/Cake.Common/Net/DownloadFileSettings.cs b/src/Cake.Common/Net/DownloadFileSettings.cs index 49c2d21e73..4a2f60f733 100644 --- a/src/Cake.Common/Net/DownloadFileSettings.cs +++ b/src/Cake.Common/Net/DownloadFileSettings.cs @@ -18,5 +18,13 @@ public sealed class DownloadFileSettings /// Gets or sets the Password to use when downloading the file /// public string Password { get; set; } + + /// + /// Gets or sets a value indicating whether default credentials are sent when downloading the file + /// + /// + /// If set to true, any Username and Password that has been speficied will be ignored. + /// + public bool UseDefaultCredentials { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Net/HttpAliases.cs b/src/Cake.Common/Net/HttpAliases.cs index 6554c069e7..95fb9be258 100644 --- a/src/Cake.Common/Net/HttpAliases.cs +++ b/src/Cake.Common/Net/HttpAliases.cs @@ -197,12 +197,15 @@ public static void DownloadFile(this ICakeContext context, Uri address, FilePath // We track the last posted value since the event seems to fire many times for the same value. var percentComplete = 0; - using (var http = new HttpClient()) + using (var http = GetHttpClient(context, settings.UseDefaultCredentials)) { - if (!string.IsNullOrWhiteSpace(settings.Username) && !string.IsNullOrWhiteSpace(settings.Password)) + if (!settings.UseDefaultCredentials) { - var byteArray = Encoding.ASCII.GetBytes(string.Concat(settings.Username, ":", settings.Password)); - http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + if (!string.IsNullOrWhiteSpace(settings.Username) && !string.IsNullOrWhiteSpace(settings.Password)) + { + var byteArray = Encoding.ASCII.GetBytes(string.Concat(settings.Username, ":", settings.Password)); + http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + } } var progress = new Progress(progressPercentage => @@ -252,7 +255,7 @@ public static void UploadFile(this ICakeContext context, Uri address, FilePath f } context.Log.Verbose("Uploading file: {0}", address); - using (var client = new HttpClient()) + using (var client = GetHttpClient(context, false)) { client.UploadFileAsync(address, filePath.FullPath).Wait(); } @@ -309,7 +312,7 @@ public static void UploadFile(this ICakeContext context, Uri address, byte[] dat } context.Log.Verbose("Uploading file: {0}", address); - using (var client = new HttpClient()) + using (var client = GetHttpClient(context, false)) { client.UploadFileAsync(address, data, fileName).Wait(); } @@ -335,5 +338,19 @@ public static void UploadFile(this ICakeContext context, string address, byte[] { UploadFile(context, new Uri(address), data, fileName); } + + /// + /// Gets an pre-populated with the correct default headers such as User-Agent. + /// The returned client should be disposed of by the caller. + /// + /// The current Cake context. + /// Indicates whether or not to use default credentials. + /// A instance. + private static HttpClient GetHttpClient(ICakeContext context, bool useDefaultCredentials) + { + var client = useDefaultCredentials ? new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }) : new HttpClient(); + client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Cake", context.Environment.Runtime.CakeVersion.ToString())); + return client; + } } } \ No newline at end of file diff --git a/src/Cake.Common/ReleaseNotesAliases.cs b/src/Cake.Common/ReleaseNotesAliases.cs index 283bd0bf05..ab7ca2a140 100644 --- a/src/Cake.Common/ReleaseNotesAliases.cs +++ b/src/Cake.Common/ReleaseNotesAliases.cs @@ -66,7 +66,7 @@ public static IReadOnlyList ParseAllReleaseNotes(this ICakeContext var file = context.FileSystem.GetFile(filePath); if (!file.Exists) { - const string format = "Release notes file '{0}' do not exist."; + const string format = "Release notes file '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, filePath.FullPath); throw new CakeException(message); } diff --git a/src/Cake.Common/Solution/Project/ProjectParser.cs b/src/Cake.Common/Solution/Project/ProjectParser.cs index f2dbd87aed..968c5ff45a 100644 --- a/src/Cake.Common/Solution/Project/ProjectParser.cs +++ b/src/Cake.Common/Solution/Project/ProjectParser.cs @@ -59,7 +59,7 @@ public ProjectParserResult Parse(FilePath projectPath) var file = _fileSystem.GetFile(projectPath); if (!file.Exists) { - const string format = "Project file '{0}' do not exist."; + const string format = "Project file '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, projectPath.FullPath); throw new CakeException(message); } diff --git a/src/Cake.Common/Solution/SolutionParser.cs b/src/Cake.Common/Solution/SolutionParser.cs index 20ea849c18..2ee2253e8d 100644 --- a/src/Cake.Common/Solution/SolutionParser.cs +++ b/src/Cake.Common/Solution/SolutionParser.cs @@ -59,7 +59,7 @@ public SolutionParserResult Parse(FilePath solutionPath) var file = _fileSystem.GetFile(solutionPath); if (!file.Exists) { - const string format = "Solution file '{0}' do not exist."; + const string format = "Solution file '{0}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, solutionPath.FullPath); throw new CakeException(message); } diff --git a/src/Cake.Common/Tools/Cake/CakeRunner.cs b/src/Cake.Common/Tools/Cake/CakeRunner.cs index c239f8207c..044f4de1e4 100644 --- a/src/Cake.Common/Tools/Cake/CakeRunner.cs +++ b/src/Cake.Common/Tools/Cake/CakeRunner.cs @@ -11,6 +11,7 @@ using System.Text; using Cake.Core; using Cake.Core.IO; +using Cake.Core.Polyfill; using Cake.Core.Tooling; namespace Cake.Common.Tools.Cake @@ -23,7 +24,17 @@ public sealed class CakeRunner : Tool private readonly ICakeEnvironment _environment; private readonly IFileSystem _fileSystem; private readonly IGlobber _globber; - private static readonly IEnumerable _executingAssemblyToolPaths = new FilePath[] { System.Reflection.Assembly.GetEntryAssembly().Location }; + private static readonly IEnumerable _executingAssemblyToolPaths; + + /// + /// Initializes static members of the class. + /// + static CakeRunner() + { + var entryAssembly = AssemblyHelper.GetExecutingAssembly(); + var executingAssemblyToolPath = entryAssembly.Location; + _executingAssemblyToolPaths = new FilePath[] { executingAssemblyToolPath }; + } /// /// Initializes a new instance of the class. diff --git a/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyseSettings.cs b/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyseSettings.cs index a9acc6a007..9fdfeabad1 100644 --- a/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyseSettings.cs +++ b/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyseSettings.cs @@ -7,7 +7,7 @@ namespace Cake.Common.Tools.DotCover.Analyse /// /// Contains settings used by . /// - public sealed class DotCoverAnalyseSettings : DotCoverSettings + public sealed class DotCoverAnalyseSettings : DotCoverCoverageSettings { /// /// Gets or sets the type of the report. diff --git a/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyser.cs b/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyser.cs index 9d7281e88d..f29f43de96 100644 --- a/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyser.cs +++ b/src/Cake.Common/Tools/DotCover/Analyse/DotCoverAnalyser.cs @@ -12,7 +12,7 @@ namespace Cake.Common.Tools.DotCover.Analyse /// /// DotCover Analyser builder. /// - public sealed class DotCoverAnalyser : DotCoverTool + public sealed class DotCoverAnalyser : DotCoverCoverageTool { private readonly ICakeEnvironment _environment; @@ -61,31 +61,13 @@ public void Analyse(ICakeContext context, throw new ArgumentNullException(nameof(settings)); } - // Run the tool using the interceptor. - var interceptor = InterceptAction(context, action); - // Run the tool. - Run(settings, GetArguments(interceptor, settings, outputPath)); - } - - private static DotCoverContext InterceptAction( - ICakeContext context, - Action action) - { - var interceptor = new DotCoverContext(context); - action(interceptor); - - // Validate arguments. - if (interceptor.FilePath == null) - { - throw new CakeException("No tool was started."); - } - - return interceptor; + Run(settings, GetArguments(context, action, settings, outputPath)); } private ProcessArgumentBuilder GetArguments( - DotCoverContext context, + ICakeContext context, + Action action, DotCoverAnalyseSettings settings, FilePath outputPath) { @@ -93,16 +75,8 @@ private ProcessArgumentBuilder GetArguments( builder.Append("Analyse"); - // The target application to call. - builder.AppendSwitch("/TargetExecutable", "=", context.FilePath.FullPath.Quote()); - - // The arguments to the target application. - var arguments = context.Settings?.Arguments?.Render(); - if (!string.IsNullOrWhiteSpace(arguments)) - { - arguments = arguments.Replace("\"", "\\\""); - builder.AppendSwitch("/TargetArguments", "=", arguments.Quote()); - } + // Get Target executable arguments + GetTargetArguments(context, action).CopyTo(builder); // Set the output file. outputPath = outputPath.MakeAbsolute(_environment); @@ -114,38 +88,11 @@ private ProcessArgumentBuilder GetArguments( builder.AppendSwitch("/ReportType", "=", settings.ReportType.ToString()); } - // TargetWorkingDir - if (settings.TargetWorkingDir != null) - { - builder.AppendSwitch("/TargetWorkingDir", "=", settings.TargetWorkingDir.MakeAbsolute(_environment).FullPath.Quote()); - } + // Get Coverage arguments + GetCoverageArguments(settings).CopyTo(builder); - // Scope - if (settings.Scope.Count > 0) - { - var scope = string.Join(";", settings.Scope); - builder.AppendSwitch("/Scope", "=", scope.Quote()); - } - - // Filters - if (settings.Filters.Count > 0) - { - var filters = string.Join(";", settings.Filters); - builder.AppendSwitch("/Filters", "=", filters.Quote()); - } - - // Filters - if (settings.AttributeFilters.Count > 0) - { - var attributeFilters = string.Join(";", settings.AttributeFilters); - builder.AppendSwitch("/AttributeFilters", "=", attributeFilters.Quote()); - } - - // DisableDefaultFilters - if (settings.DisableDefaultFilters) - { - builder.Append("/DisableDefaultFilters"); - } + // Get base arguments + GetArguments(settings).CopyTo(builder); return builder; } diff --git a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs index 59c422aeb7..6fd5c47a94 100644 --- a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs +++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs @@ -7,7 +7,7 @@ namespace Cake.Common.Tools.DotCover.Cover /// /// Contains settings used by . /// - public sealed class DotCoverCoverSettings : DotCoverSettings + public sealed class DotCoverCoverSettings : DotCoverCoverageSettings { } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs index e7c366dfab..7ea228a986 100644 --- a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs +++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs @@ -12,7 +12,7 @@ namespace Cake.Common.Tools.DotCover.Cover /// /// DotCover Coverer builder. /// - public sealed class DotCoverCoverer : DotCoverTool + public sealed class DotCoverCoverer : DotCoverCoverageTool { private readonly ICakeEnvironment _environment; @@ -61,31 +61,13 @@ public void Cover(ICakeContext context, throw new ArgumentNullException(nameof(settings)); } - // Run the tool using the interceptor. - var interceptor = InterceptAction(context, action); - // Run the tool. - Run(settings, GetArguments(interceptor, settings, outputPath)); - } - - private static DotCoverContext InterceptAction( - ICakeContext context, - Action action) - { - var interceptor = new DotCoverContext(context); - action(interceptor); - - // Validate arguments. - if (interceptor.FilePath == null) - { - throw new CakeException("No tool was started."); - } - - return interceptor; + Run(settings, GetArguments(context, action, settings, outputPath)); } private ProcessArgumentBuilder GetArguments( - DotCoverContext context, + ICakeContext context, + Action action, DotCoverCoverSettings settings, FilePath outputPath) { @@ -93,53 +75,18 @@ private ProcessArgumentBuilder GetArguments( builder.Append("Cover"); - // The target application to call. - builder.AppendSwitch("/TargetExecutable", "=", context.FilePath.FullPath.Quote()); - - // The arguments to the target application. - var arguments = context.Settings?.Arguments?.Render(); - if (!string.IsNullOrWhiteSpace(arguments)) - { - arguments = arguments.Replace("\"", "\\\""); - builder.AppendSwitch("/TargetArguments", "=", arguments.Quote()); - } + // Get Target executable arguments + GetTargetArguments(context, action).CopyTo(builder); // Set the output file. outputPath = outputPath.MakeAbsolute(_environment); builder.AppendSwitch("/Output", "=", outputPath.FullPath.Quote()); - // TargetWorkingDir - if (settings.TargetWorkingDir != null) - { - builder.AppendSwitch("/TargetWorkingDir", "=", settings.TargetWorkingDir.MakeAbsolute(_environment).FullPath.Quote()); - } + // Get Coverage arguments + GetCoverageArguments(settings).CopyTo(builder); - // Scope - if (settings.Scope.Count > 0) - { - var scope = string.Join(";", settings.Scope); - builder.AppendSwitch("/Scope", "=", scope.Quote()); - } - - // Filters - if (settings.Filters.Count > 0) - { - var filters = string.Join(";", settings.Filters); - builder.AppendSwitch("/Filters", "=", filters.Quote()); - } - - // Filters - if (settings.AttributeFilters.Count > 0) - { - var attributeFilters = string.Join(";", settings.AttributeFilters); - builder.AppendSwitch("/AttributeFilters", "=", attributeFilters.Quote()); - } - - // DisableDefaultFilters - if (settings.DisableDefaultFilters) - { - builder.Append("/DisableDefaultFilters"); - } + // Get base arguments + GetArguments(settings).CopyTo(builder); return builder; } diff --git a/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs b/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs index b7ceb79b49..87e7f9fe60 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs @@ -5,6 +5,7 @@ using System; using Cake.Common.Tools.DotCover.Analyse; using Cake.Common.Tools.DotCover.Cover; +using Cake.Common.Tools.DotCover.Report; using Cake.Core; using Cake.Core.Annotations; using Cake.Core.IO; @@ -123,5 +124,50 @@ public static void DotCoverCover( // Run DotCover cover. coverer.Cover(context, action, outputFile, settings); } + + /// + /// Runs DotCover Report + /// for the specified action and settings. + /// + /// The context. + /// The DotCover coverage snapshot file name. + /// The DotCover output file. + /// The settings + /// + /// + /// DotCoverReport(new FilePath("./result.dcvr"), + /// new FilePath("./result.html"), + /// new DotCoverReportSettings { + /// ReportType = DotCoverReportType.HTML + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Report")] + [CakeNamespaceImport("Cake.Common.Tools.DotCover.Report")] + public static void DotCoverReport( + this ICakeContext context, + FilePath sourceFile, + FilePath outputFile, + DotCoverReportSettings settings) + { + if (context == null) + { + throw new ArgumentNullException("context"); + } + + if (settings == null) + { + settings = new DotCoverReportSettings(); + } + + // Create the DotCover reporter. + var reporter = new DotCoverReporter( + context.FileSystem, context.Environment, + context.ProcessRunner, context.Tools); + + // Run DotCover report. + reporter.Report(sourceFile, outputFile, settings); + } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs new file mode 100644 index 0000000000..4b4273e421 --- /dev/null +++ b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotCover +{ + /// + /// Contains settings used by . + /// + public abstract class DotCoverCoverageSettings : DotCoverSettings + { + private readonly HashSet _scope; + private readonly HashSet _filters; + private readonly HashSet _attributeFilters; + + /// + /// Gets or sets program working directory + /// This represents the /TargetWorkingDir option. + /// + public DirectoryPath TargetWorkingDir { get; set; } + + /// + /// Gets the assemblies loaded in the specified scope into coverage results. + /// Ant-style patterns are supported here (e.g.ProjectFolder/**/*.dll) + /// This represents the /Scope option. + /// + public ISet Scope + { + get { return _scope; } + } + + /// + /// Gets the coverage filters using the following syntax: +:module=*;class=*;function=*; + /// Use -:myassembly to exclude an assembly from code coverage. + /// Asterisk wildcard (*) is supported here. + /// This represents the /Filters option. + /// + public ISet Filters + { + get { return _filters; } + } + + /// + /// Gets the attribute filters using the following syntax: filter1;filter2;... + /// Asterisk wildcard(*) is supported here + /// This represents the /AttributeFilters option. + /// + public ISet AttributeFilters + { + get { return _attributeFilters; } + } + + /// + /// Gets or sets a value indicating whether the default (automatically added) filters should be disabled + /// This represents the /DisableDefaultFilters option. + /// + public bool DisableDefaultFilters { get; set; } + + /// + /// Initializes a new instance of the class. + /// + protected DotCoverCoverageSettings() + { + _scope = new HashSet(StringComparer.Ordinal); + _filters = new HashSet(StringComparer.OrdinalIgnoreCase); + _attributeFilters = new HashSet(StringComparer.OrdinalIgnoreCase); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/DotCoverSettingsExtensions.cs b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs similarity index 62% rename from src/Cake.Common/Tools/DotCover/DotCoverSettingsExtensions.cs rename to src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs index eebffd74cf..1ee58c4d20 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverSettingsExtensions.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs @@ -3,26 +3,28 @@ // See the LICENSE file in the project root for more information. using System; +using Cake.Core; +using Cake.Core.IO; namespace Cake.Common.Tools.DotCover { /// - /// Contains extensions for . + /// Contains extensions for . /// - public static class DotCoverSettingsExtensions + public static class DotCoverCoverageSettingsExtensions { /// /// Adds the scope. /// /// The settings. /// The scope. - /// The settings type, derived from - /// The same instance so that multiple calls can be chained. - public static T WithScope(this T settings, string scope) where T : DotCoverSettings + /// The settings type, derived from + /// The same instance so that multiple calls can be chained. + public static T WithScope(this T settings, string scope) where T : DotCoverCoverageSettings { if (settings == null) { - throw new ArgumentNullException(nameof(settings)); + throw new ArgumentNullException("settings"); } settings.Scope.Add(scope); return settings; @@ -33,13 +35,13 @@ public static T WithScope(this T settings, string scope) where T : DotCoverSe /// /// The settings. /// The filter. - /// The settings type, derived from - /// The same instance so that multiple calls can be chained. - public static T WithFilter(this T settings, string filter) where T : DotCoverSettings + /// The settings type, derived from + /// The same instance so that multiple calls can be chained. + public static T WithFilter(this T settings, string filter) where T : DotCoverCoverageSettings { if (settings == null) { - throw new ArgumentNullException(nameof(settings)); + throw new ArgumentNullException("settings"); } settings.Filters.Add(filter); return settings; @@ -50,13 +52,13 @@ public static T WithFilter(this T settings, string filter) where T : DotCover /// /// The settings. /// The filter. - /// The settings type, derived from - /// The same instance so that multiple calls can be chained. - public static T WithAttributeFilter(this T settings, string attributeFilter) where T : DotCoverSettings + /// The settings type, derived from + /// The same instance so that multiple calls can be chained. + public static T WithAttributeFilter(this T settings, string attributeFilter) where T : DotCoverCoverageSettings { if (settings == null) { - throw new ArgumentNullException(nameof(settings)); + throw new ArgumentNullException("settings"); } settings.AttributeFilters.Add(attributeFilter); return settings; diff --git a/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs b/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs new file mode 100644 index 0000000000..c3add4ebd8 --- /dev/null +++ b/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs @@ -0,0 +1,127 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotCover +{ + /// + /// DotCover Coverage tool. + /// + /// The settings type + public abstract class DotCoverCoverageTool : DotCoverTool where TSettings : DotCoverCoverageSettings + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public DotCoverCoverageTool( + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator tools) : base(fileSystem, environment, processRunner, tools) + { + _environment = environment; + } + + /// + /// Get arguments from the target executable + /// + /// The context. + /// The action to run DotCover for. + /// The process arguments + protected ProcessArgumentBuilder GetTargetArguments(ICakeContext context, Action action) + { + // Run the tool using the interceptor. + var targetContext = InterceptAction(context, action); + + var builder = new ProcessArgumentBuilder(); + + // The target application to call. + builder.AppendSwitch("/TargetExecutable", "=", targetContext.FilePath.FullPath.Quote()); + + // The arguments to the target application. + if (targetContext.Settings != null && targetContext.Settings.Arguments != null) + { + var arguments = targetContext.Settings.Arguments.Render(); + if (!string.IsNullOrWhiteSpace(arguments)) + { + arguments = arguments.Replace("\"", "\\\""); + builder.AppendSwitch("/TargetArguments", "=", arguments.Quote()); + } + } + + return builder; + } + + /// + /// Get arguments from coverage settings + /// + /// The settings + /// The process arguments + protected ProcessArgumentBuilder GetCoverageArguments(DotCoverCoverageSettings settings) + { + var builder = new ProcessArgumentBuilder(); + + // TargetWorkingDir + if (settings.TargetWorkingDir != null) + { + builder.AppendSwitch("/TargetWorkingDir", "=", settings.TargetWorkingDir.MakeAbsolute(_environment).FullPath.Quote()); + } + + // Scope + if (settings.Scope.Count > 0) + { + var scope = string.Join(";", settings.Scope); + builder.AppendSwitch("/Scope", "=", scope.Quote()); + } + + // Filters + if (settings.Filters.Count > 0) + { + var filters = string.Join(";", settings.Filters); + builder.AppendSwitch("/Filters", "=", filters.Quote()); + } + + // Filters + if (settings.AttributeFilters.Count > 0) + { + var attributeFilters = string.Join(";", settings.AttributeFilters); + builder.AppendSwitch("/AttributeFilters", "=", attributeFilters.Quote()); + } + + // DisableDefaultFilters + if (settings.DisableDefaultFilters) + { + builder.Append("/DisableDefaultFilters"); + } + + return builder; + } + + private static DotCoverContext InterceptAction( + ICakeContext context, + Action action) + { + var interceptor = new DotCoverContext(context); + action(interceptor); + + // Validate arguments. + if (interceptor.FilePath == null) + { + throw new CakeException("No tool was started."); + } + + return interceptor; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/DotCoverProcessRunner.cs b/src/Cake.Common/Tools/DotCover/DotCoverProcessRunner.cs index 70e0fd1bae..ed350a5521 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverProcessRunner.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverProcessRunner.cs @@ -34,6 +34,11 @@ public int GetExitCode() return 0; } + public IEnumerable GetStandardError() + { + return Enumerable.Empty(); + } + public IEnumerable GetStandardOutput() { return Enumerable.Empty(); diff --git a/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs b/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs index 79b1ee2146..516ced752a 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs @@ -1,10 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using Cake.Core.IO; +using Cake.Core.IO; using Cake.Core.Tooling; namespace Cake.Common.Tools.DotCover @@ -14,52 +8,10 @@ namespace Cake.Common.Tools.DotCover /// public abstract class DotCoverSettings : ToolSettings { - private readonly HashSet _scope; - private readonly HashSet _filters; - private readonly HashSet _attributeFilters; - - /// - /// Gets or sets program working directory - /// This represents the /TargetWorkingDir option. - /// - public DirectoryPath TargetWorkingDir { get; set; } - - /// - /// Gets the assemblies loaded in the specified scope into coverage results. - /// Ant-style patterns are supported here (e.g.ProjectFolder/**/*.dll) - /// This represents the /Scope option. - /// - public ISet Scope => _scope; - - /// - /// Gets the coverage filters using the following syntax: +:module=*;class=*;function=*; - /// Use -:myassembly to exclude an assembly from code coverage. - /// Asterisk wildcard (*) is supported here. - /// This represents the /Filters option. - /// - public ISet Filters => _filters; - - /// - /// Gets the attribute filters using the following syntax: filter1;filter2;... - /// Asterisk wildcard(*) is supported here - /// This represents the /AttributeFilters option. - /// - public ISet AttributeFilters => _attributeFilters; - - /// - /// Gets or sets a value indicating whether the default (automatically added) filters should be disabled - /// This represents the /DisableDefaultFilters option. - /// - public bool DisableDefaultFilters { get; set; } - /// - /// Initializes a new instance of the class. + /// Gets or sets a value that enables logging and specifies log file name + /// This represents the /LogFile option. /// - protected DotCoverSettings() - { - _scope = new HashSet(StringComparer.Ordinal); - _filters = new HashSet(StringComparer.OrdinalIgnoreCase); - _attributeFilters = new HashSet(StringComparer.OrdinalIgnoreCase); - } + public FilePath LogFile { get; set; } } -} \ No newline at end of file +} diff --git a/src/Cake.Common/Tools/DotCover/DotCoverTool.cs b/src/Cake.Common/Tools/DotCover/DotCoverTool.cs index 89f25ba57c..b1958800f3 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverTool.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverTool.cs @@ -14,8 +14,10 @@ namespace Cake.Common.Tools.DotCover /// /// The settings type public abstract class DotCoverTool : Tool - where TSettings : ToolSettings + where TSettings : DotCoverSettings { + private readonly ICakeEnvironment _environment; + /// /// Initializes a new instance of the class. /// @@ -29,6 +31,7 @@ protected DotCoverTool( IProcessRunner processRunner, IToolLocator tools) : base(fileSystem, environment, processRunner, tools) { + _environment = environment; } /// @@ -48,5 +51,24 @@ protected override IEnumerable GetToolExecutableNames() { return new[] { "dotCover.exe" }; } + + /// + /// Get arguments from global settings + /// + /// The settings + /// The process arguments + protected ProcessArgumentBuilder GetArguments(DotCoverSettings settings) + { + var builder = new ProcessArgumentBuilder(); + + // LogFile + if (settings.LogFile != null) + { + var logFilePath = settings.LogFile.MakeAbsolute(_environment); + builder.AppendSwitch("/LogFile", "=", logFilePath.FullPath.Quote()); + } + + return builder; + } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs b/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs new file mode 100644 index 0000000000..c9df3ac060 --- /dev/null +++ b/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs @@ -0,0 +1,17 @@ +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotCover.Report +{ + /// + /// Contains settings used by . + /// + public sealed class DotCoverReportSettings : DotCoverSettings + { + /// + /// Gets or sets the type of the report. + /// This represents the /ReportType option. + /// The Default value is . + /// + public DotCoverReportType ReportType { get; set; } + } +} diff --git a/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs b/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs new file mode 100644 index 0000000000..a9b5d67b4d --- /dev/null +++ b/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotCover.Report +{ + /// + /// DotCover Report reporter. + /// + public sealed class DotCoverReporter : DotCoverTool + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public DotCoverReporter( + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator tools) : base(fileSystem, environment, processRunner, tools) + { + _environment = environment; + } + + /// + /// Runs DotCover Cover with the specified settings. + /// + /// The DotCover coverage snapshot file name. + /// The DotCover output file. + /// The settings + public void Report( + FilePath sourceFile, + FilePath outputFile, + DotCoverReportSettings settings) + { + if (sourceFile == null) + { + throw new ArgumentNullException("sourceFile"); + } + if (outputFile == null) + { + throw new ArgumentNullException("outputFile"); + } + if (settings == null) + { + throw new ArgumentNullException("settings"); + } + + // Run the tool. + Run(settings, GetArguments(sourceFile, outputFile, settings)); + } + + private ProcessArgumentBuilder GetArguments( + FilePath sourceFile, + FilePath outputFile, + DotCoverReportSettings settings) + { + var builder = new ProcessArgumentBuilder(); + + builder.Append("Report"); + + // Set the Source file. + sourceFile = sourceFile.MakeAbsolute(_environment); + builder.AppendSwitch("/Source", "=", sourceFile.FullPath.Quote()); + + // Set the Output file. + outputFile = outputFile.MakeAbsolute(_environment); + builder.AppendSwitch("/Output", "=", outputFile.FullPath.Quote()); + + // Set the report type, don't include the default value + if (settings.ReportType != DotCoverReportType.XML) + { + builder.AppendSwitch("/ReportType", "=", settings.ReportType.ToString()); + } + + // Get Global settings + GetArguments(settings).CopyTo(builder); + + return builder; + } + } +} diff --git a/src/Cake.Common/Tools/InnoSetup/InnoSetupAliases.cs b/src/Cake.Common/Tools/InnoSetup/InnoSetupAliases.cs new file mode 100644 index 0000000000..4c9c2eb9af --- /dev/null +++ b/src/Cake.Common/Tools/InnoSetup/InnoSetupAliases.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.InnoSetup +{ + /// + /// Contains functionality related to Inno Setup. + /// + /// In order to use the commands for this alias, Inno Setup will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to download/install. + /// + /// + [CakeAliasCategory("Inno Setup")] + public static class InnoSetupAliases + { + /// + /// Compiles the given Inno Setup script using the default settings. + /// + /// The context. + /// The path to the .nsi script file to compile. + /// + /// + /// InnoSetup("./src/Cake.iss"); + /// + /// + [CakeMethodAlias] + public static void InnoSetup(this ICakeContext context, FilePath scriptFile) + { + InnoSetup(context, scriptFile, new InnoSetupSettings()); + } + + /// + /// Compiles the given Inno Setup script using the given . + /// + /// The context. + /// The path to the .nsi script file to compile. + /// The to use. + /// + /// + /// InnoSetup("./src/Cake.iss", new InnoSetupSettings { + /// OutputDir = outputDirectory + /// }); + /// + /// + [CakeMethodAlias] + public static void InnoSetup(this ICakeContext context, FilePath scriptFile, InnoSetupSettings settings) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (scriptFile == null) + { + throw new ArgumentNullException(nameof(scriptFile)); + } + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + + var runner = new InnoSetupRunner(context.FileSystem, context.Registry, context.Environment, context.ProcessRunner, context.Tools); + runner.Run(scriptFile, settings); + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/InnoSetup/InnoSetupQuietMode.cs b/src/Cake.Common/Tools/InnoSetup/InnoSetupQuietMode.cs new file mode 100644 index 0000000000..4bb0babf2b --- /dev/null +++ b/src/Cake.Common/Tools/InnoSetup/InnoSetupQuietMode.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Cake.Common.Tools.InnoSetup +{ + /// + /// Represents the possible quiet modes when compiling an Inno Setup script. + /// + public enum InnoSetupQuietMode + { + /// + /// Quiet mode disabled. This is the default value. + /// + Off, + + /// + /// Quiet mode. Only error messages are printed. + /// + Quiet, + + /// + /// Quiet mode with progress. Same as quiet mode, but also displays progress. + /// + QuietWithProgress + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/InnoSetup/InnoSetupRunner.cs b/src/Cake.Common/Tools/InnoSetup/InnoSetupRunner.cs new file mode 100644 index 0000000000..159045db3f --- /dev/null +++ b/src/Cake.Common/Tools/InnoSetup/InnoSetupRunner.cs @@ -0,0 +1,159 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.IO.Arguments; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.InnoSetup +{ + /// + /// The runner which executes Inno Setup. + /// + public sealed class InnoSetupRunner : Tool + { + private readonly IRegistry _registry; + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The registry. + /// The environment. + /// The process runner. + /// The tool locator. + public InnoSetupRunner( + IFileSystem fileSystem, + IRegistry registry, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator tools) : base(fileSystem, environment, processRunner, tools) + { + _registry = registry; + _environment = environment; + } + + /// + /// Runs iscc.exe with the specified script files and settings. + /// + /// The script file (.iss) to compile. + /// The settings. + public void Run(FilePath scriptFile, InnoSetupSettings settings) + { + if (scriptFile == null) + { + throw new ArgumentNullException(nameof(scriptFile)); + } + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + Run(settings, GetArguments(scriptFile, settings)); + } + + /// + /// Gets the name of the tool. + /// + /// The name of the tool. + protected override string GetToolName() + { + return "InnoSetup"; + } + + /// + /// Gets the possible names of the tool executable. + /// + /// The tool executable name. + protected override IEnumerable GetToolExecutableNames() + { + return new[] { "iscc.exe" }; + } + + /// + /// Gets alternative file paths which the tool may exist in + /// + /// The settings. + /// The default tool path. + protected override IEnumerable GetAlternativeToolPaths(InnoSetupSettings settings) + { + // On 64-bit Windows, the registry key for Inno Setup will be accessible under Wow6432Node + string keyPath = _environment.Platform.Is64Bit + ? @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 5_is1" + : @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 5_is1"; + + using (var innoSetupKey = _registry.LocalMachine.OpenKey(keyPath)) + { + string installationPath = innoSetupKey?.GetValue("InstallLocation") as string; + if (!string.IsNullOrEmpty(installationPath)) + { + var directory = new DirectoryPath(installationPath); + var isccPath = directory.CombineWithFilePath("iscc.exe"); + return new[] { isccPath }; + } + } + + return base.GetAlternativeToolPaths(settings); + } + + private ProcessArgumentBuilder GetArguments(FilePath scriptFile, InnoSetupSettings settings) + { + var builder = new ProcessArgumentBuilder(); + + // Defines (/Ddefine[=value] + if (settings.Defines != null) + { + foreach (var item in settings.Defines) + { + builder.Append(string.IsNullOrEmpty(item.Value) + ? string.Format(CultureInfo.InvariantCulture, "/D{0}", item.Key) + : string.Format(CultureInfo.InvariantCulture, "/D{0}={1}", item.Key, + new QuotedArgument(new TextArgument(item.Value)))); + } + } + + // Enable output + if (settings.EnableOutput.HasValue) + { + builder.Append(settings.EnableOutput.Value ? "/O+" : "/O-"); + } + + // Output directory + if (settings.OutputDirectory != null) + { + builder.AppendSwitchQuoted("/O", string.Empty, settings.OutputDirectory.MakeAbsolute(_environment).FullPath); + } + + // Output base file name + if (!string.IsNullOrEmpty(settings.OutputBaseFilename)) + { + builder.AppendSwitchQuoted("/F", string.Empty, settings.OutputBaseFilename); + } + + // Quiet mode + switch (settings.QuietMode) + { + case InnoSetupQuietMode.Off: + break; + case InnoSetupQuietMode.Quiet: + builder.Append("/Q"); + break; + case InnoSetupQuietMode.QuietWithProgress: + builder.Append("/Qp"); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + // Quoted Script file + builder.AppendQuoted(scriptFile.MakeAbsolute(_environment).FullPath); + + return builder; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/InnoSetup/InnoSetupSettings.cs b/src/Cake.Common/Tools/InnoSetup/InnoSetupSettings.cs new file mode 100644 index 0000000000..f0a2747798 --- /dev/null +++ b/src/Cake.Common/Tools/InnoSetup/InnoSetupSettings.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.InnoSetup +{ + /// + /// Contains settings used by the . + /// + public sealed class InnoSetupSettings : ToolSettings + { + /// + /// Gets or sets the script compiler defines. Emulates #define public preprocessor directive. + /// + public IDictionary Defines { get; set; } + + /// + /// Gets or sets whether or not the compiler should generate output (/O+ and /O- command line options, + /// overrides the script's Output attribute). + /// + public bool? EnableOutput { get; set; } + + /// + /// Gets or sets the output directory (/O<path> command line option, overrides the script's OutputDir + /// attribute). + /// + public DirectoryPath OutputDirectory { get; set; } + + /// + /// Gets or sets the output base file name (/F<filename> command line option, overrides the script's + /// OutputBaseFilename attribute). + /// + public string OutputBaseFilename { get; set; } + + /// + /// Gets or sets the script compiler's quiet mode (/Q and /Qp command line options). + /// + public InnoSetupQuietMode QuietMode { get; set; } + + /// + /// Initializes a new instance of the class with the default settings. + /// + public InnoSetupSettings() + { + Defines = new Dictionary(); + } + } +} diff --git a/src/Cake.Common/Tools/MSBuild/MSBuildFileLogger.cs b/src/Cake.Common/Tools/MSBuild/MSBuildFileLogger.cs new file mode 100644 index 0000000000..c817724c57 --- /dev/null +++ b/src/Cake.Common/Tools/MSBuild/MSBuildFileLogger.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using Cake.Core.Diagnostics; + +namespace Cake.Common.Tools.MSBuild +{ + /// + /// Contains settings for specifying a MSBuild file logger. + /// + public class MSBuildFileLogger + { + /// + /// Initializes a new instance of the class. + /// + public MSBuildFileLogger() + { + } + + /// + /// Gets or sets a value indicating whether PerformanceSummary will Show the time that’s spent in tasks, targets, and projects. + /// + public bool PerformanceSummaryEnabled { get; set; } + + /// + /// Gets or sets a value indicating whether Summary will Show the error and warning summary at the end. + /// + public bool SummaryDisabled { get; set; } + + /// + /// Gets or sets show ErrorsOnly, WarningsOnly, or All. + /// + public MSBuildFileLoggerOutput MSBuildFileLoggerOutput { get; set; } + + /// + /// Gets or sets a value indicating whether NoItemAndPropertyList will be set to Don't show the list of items and properties that would appear at the start of each project build if the verbosity level is set to diagnostic. + /// + public bool HideVerboseItemAndPropertyList { get; set; } + + /// + /// Gets or sets a value indicating whether ShowCommandLine. Show TaskCommandLineEvent messages. + /// + public bool ShowCommandLine { get; set; } + + /// + /// Gets or sets a value indicating whether ShowTimestamp. Show the timestamp as a prefix to any message. + /// + public bool ShowTimestamp { get; set; } + + /// + /// Gets or sets a value indicating whether ShowEventId. Show the event ID for each started event, finished event, and message. + /// + public bool ShowEventId { get; set; } + + /// + /// Gets or sets Verbosity. Override the /verbosity setting for this logger. + /// Specify the following verbosity levels: q[uiet], m[inimal], n[ormal], v[erbose] (detailed), and diag[nostic]. + /// + public Verbosity? Verbosity { get; set; } + + /// + /// Gets or sets LogFile. The path to the log file into which the build log is written. + /// An empty string will use msbuild.log. + /// + public string LogFile { get; set; } + + /// + /// Gets or sets a value indicating whether the build log is appended to the log file or overwrites it. When true, the build log is appended to the log file. + /// + public bool AppendToLogFile { get; set; } + + /// + /// Gets or sets Specifies the encoding for the file (for example, UTF-8, Unicode, or ASCII). + /// + public string Encoding { get; set; } + + /// + /// Process the file logger config and return parameters as a string. + /// + /// The parameters separated by semi-colons. + public string GetParameters() + { + var parameters = new List(); + parameters.Add(!string.IsNullOrWhiteSpace(LogFile) ? $"logfile={LogFile}" : null); + parameters.Add(!string.IsNullOrWhiteSpace(Encoding) ? $"Encoding={Encoding}" : null); + parameters.Add(AppendToLogFile ? "Append" : null); + parameters.Add(PerformanceSummaryEnabled ? "PerformanceSummary" : null); + parameters.Add(SummaryDisabled ? "NoSummary" : null); + parameters.Add(MSBuildFileLoggerOutput == MSBuildFileLoggerOutput.ErrorsOnly ? "ErrorsOnly" : null); + parameters.Add(MSBuildFileLoggerOutput == MSBuildFileLoggerOutput.WarningsOnly ? "WarningsOnly" : null); + parameters.Add(HideVerboseItemAndPropertyList ? "NoItemAndPropertyList" : null); + parameters.Add(ShowCommandLine ? "ShowCommandLine" : null); + parameters.Add(ShowTimestamp ? "ShowTimestamp" : null); + parameters.Add(ShowEventId ? "ShowEventId" : null); + parameters.Add(Verbosity != null ? $"Verbosity={Verbosity.Value.ToString()}" : null); + + return string.Join(";", parameters.Where(p => p != null)); + } + } +} diff --git a/src/Cake.Common/Tools/MSBuild/MSBuildFileLoggerOutput.cs b/src/Cake.Common/Tools/MSBuild/MSBuildFileLoggerOutput.cs new file mode 100644 index 0000000000..544e3b70b8 --- /dev/null +++ b/src/Cake.Common/Tools/MSBuild/MSBuildFileLoggerOutput.cs @@ -0,0 +1,23 @@ +namespace Cake.Common.Tools.MSBuild +{ + /// + /// The type of file logger output to generate. + /// + public enum MSBuildFileLoggerOutput + { + /// + /// Show errors and warnings. + /// + All = 0, + + /// + /// Show errors only. + /// + ErrorsOnly = 1, + + /// + /// Show warnings only. + /// + WarningsOnly = 2, + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/MSBuild/MSBuildRunner.cs b/src/Cake.Common/Tools/MSBuild/MSBuildRunner.cs index 49ed20cecc..ed8677bad3 100644 --- a/src/Cake.Common/Tools/MSBuild/MSBuildRunner.cs +++ b/src/Cake.Common/Tools/MSBuild/MSBuildRunner.cs @@ -58,6 +58,18 @@ private ProcessArgumentBuilder GetArguments(FilePath solution, MSBuildSettings s builder.Append(settings.MaxCpuCount > 0 ? string.Concat("/m:", settings.MaxCpuCount) : "/m"); } + // Set the detailed summary flag. + if (settings.DetailedSummary.GetValueOrDefault()) + { + builder.Append("/ds"); + } + + // Set the no console logger flag. + if (settings.NoConsoleLogger.GetValueOrDefault()) + { + builder.Append("/noconlog"); + } + // Set the verbosity. builder.Append(string.Format(CultureInfo.InvariantCulture, "/v:{0}", GetVerbosityName(settings.Verbosity))); @@ -111,28 +123,60 @@ private ProcessArgumentBuilder GetArguments(FilePath solution, MSBuildSettings s } } + // Got any file loggers? + if (settings.FileLoggers.Count > 0) + { + var arguments = settings.FileLoggers.Select((logger, index) => + { + return GetLoggerArgument(index, logger); + }); + + foreach (var argument in arguments) + { + builder.Append(argument); + } + } + // Add the solution as the last parameter. builder.AppendQuoted(solution.MakeAbsolute(_environment).FullPath); return builder; } - private static string GetLoggerArgument(MSBuildLogger logger) - { - string argument = "/logger:"; - if (!string.IsNullOrWhiteSpace(logger.Class)) - { - argument += string.Format("{0},{1}", logger.Class, logger.Assembly); - } - else - { - argument += logger.Assembly; - } - if (!string.IsNullOrWhiteSpace(logger.Parameters)) - { - argument += string.Concat(";", logger.Parameters); - } - return argument; + private static string GetLoggerArgument(int index, MSBuildFileLogger logger) + { + if (index >= 10) + { + throw new InvalidOperationException("Too Many FileLoggers"); + } + + var counter = index == 0 ? string.Empty : index.ToString(); + var argument = $"/fl{counter}"; + + var parameters = logger.GetParameters(); + if (!string.IsNullOrWhiteSpace(parameters)) + { + argument = $"{argument} /flp{counter}:{parameters}"; + } + return argument; + } + + private static string GetLoggerArgument(MSBuildLogger logger) + { + string argument = "/logger:"; + if (!string.IsNullOrWhiteSpace(logger.Class)) + { + argument += string.Format("{0},{1}", logger.Class, logger.Assembly); + } + else + { + argument += logger.Assembly; + } + if (!string.IsNullOrWhiteSpace(logger.Parameters)) + { + argument += string.Concat(";", logger.Parameters); + } + return argument; } private static string GetPlatformName(PlatformTarget platform, bool isSolution) diff --git a/src/Cake.Common/Tools/MSBuild/MSBuildSettings.cs b/src/Cake.Common/Tools/MSBuild/MSBuildSettings.cs index 677c06c0ac..9f197af1da 100644 --- a/src/Cake.Common/Tools/MSBuild/MSBuildSettings.cs +++ b/src/Cake.Common/Tools/MSBuild/MSBuildSettings.cs @@ -17,6 +17,7 @@ public sealed class MSBuildSettings : ToolSettings private readonly HashSet _targets; private readonly Dictionary> _properties; private readonly List _loggers; + private readonly List _fileLoggers; /// /// Gets the targets. @@ -57,7 +58,8 @@ public sealed class MSBuildSettings : ToolSettings /// /// Gets or sets the maximum CPU count. /// If this value is zero, MSBuild will use as many processes as - /// there are available CPUs to build the project. + /// there are available CPUs to build the project. If not set + /// MSBuild compile projects in this solution one at a time. /// /// The maximum CPU count. public int? MaxCpuCount { get; set; } @@ -69,6 +71,21 @@ public sealed class MSBuildSettings : ToolSettings /// public bool? NodeReuse { get; set; } + /// + /// Gets or sets whether or not detailed summary is created. + /// Shows detailed information at the end of the build + /// about the configurations built and how they were + /// scheduled to nodes. + /// + public bool? DetailedSummary { get; set; } + + /// + /// Gets or sets whether or not information is logged to the console. + /// Disable the default console logger and do not log events + /// to the console. + /// + public bool? NoConsoleLogger { get; set; } + /// /// Gets or sets the amount of information to display in the build log. /// Each logger displays events based on the verbosity level that you set for that logger. @@ -81,6 +98,11 @@ public sealed class MSBuildSettings : ToolSettings /// public ICollection Loggers => _loggers; + /// + /// Gets the file loggers + /// + public ICollection FileLoggers => _fileLoggers; + /// /// Initializes a new instance of the class. /// @@ -89,6 +111,7 @@ public MSBuildSettings() _targets = new HashSet(StringComparer.OrdinalIgnoreCase); _properties = new Dictionary>(StringComparer.OrdinalIgnoreCase); _loggers = new List(); + _fileLoggers = new List(); ToolVersion = MSBuildToolVersion.Default; Configuration = string.Empty; diff --git a/src/Cake.Common/Tools/MSBuild/MSBuildSettingsExtensions.cs b/src/Cake.Common/Tools/MSBuild/MSBuildSettingsExtensions.cs index a8f8b9079f..fc522c6b2e 100644 --- a/src/Cake.Common/Tools/MSBuild/MSBuildSettingsExtensions.cs +++ b/src/Cake.Common/Tools/MSBuild/MSBuildSettingsExtensions.cs @@ -120,7 +120,7 @@ public static MSBuildSettings SetConfiguration(this MSBuildSettings settings, st } /// - /// Sets the maximum CPU count. + /// Sets the maximum CPU count. Without this set MSBuild will compile projects in this solution one at a time. /// /// The settings. /// The maximum CPU count. Set this value to zero to use as many MSBuild processes as available CPUs. @@ -158,6 +158,38 @@ public static MSBuildSettings SetNodeReuse(this MSBuildSettings settings, bool r return settings; } + /// + /// Sets whether or not detailed summary should be enabled. + /// + /// The settings. + /// true if detailed summary should be enabled; otherwise false. + /// The same instance so that multiple calls can be chained. + public static MSBuildSettings SetDetailedSummary(this MSBuildSettings settings, bool detailedSummary) + { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + settings.DetailedSummary = detailedSummary; + return settings; + } + + /// + /// Sets whether or not no console logging should be enabled. + /// + /// The settings. + /// true if no console log should be enabled; otherwise false. + /// The same instance so that multiple calls can be chained. + public static MSBuildSettings SetNoConsoleLogger(this MSBuildSettings settings, bool noConsoleLog) + { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + settings.NoConsoleLogger = noConsoleLog; + return settings; + } + /// /// Sets the build log verbosity. /// @@ -172,15 +204,15 @@ public static MSBuildSettings SetVerbosity(this MSBuildSettings settings, Verbos } settings.Verbosity = verbosity; return settings; - } - - /// - /// Adds a custom logger. - /// - /// The settings. - /// The assembly containing the logger. Should match the format {AssemblyName[,StrongName] | AssemblyFile} - /// The class implementing the logger. Should match the format [PartialOrFullNamespace.]LoggerClassName. If the assembly contains only one logger, class does not need to be specified. - /// Parameters to be passed to the logger. + } + + /// + /// Adds a custom logger. + /// + /// The settings. + /// The assembly containing the logger. Should match the format {AssemblyName[,StrongName] | AssemblyFile} + /// The class implementing the logger. Should match the format [PartialOrFullNamespace.]LoggerClassName. If the assembly contains only one logger, class does not need to be specified. + /// Parameters to be passed to the logger. /// The same instance so that multiple calls can be chained. public static MSBuildSettings WithLogger(this MSBuildSettings settings, string loggerAssembly, string loggerClass = null, string loggerParameters = null) { @@ -200,5 +232,48 @@ public static MSBuildSettings WithLogger(this MSBuildSettings settings, string l }); return settings; } + + /// + /// Adds a file logger. + /// Each file logger will be declared in the order added. + /// The first file logger will match up to the /fl parameter. + /// The next nine (max) file loggers will match up to the /fl1 through /fl9 respectively. + /// + /// The settings. + /// Parameters to be passed to the logger. + /// The same instance so that multiple calls can be chained. + public static MSBuildSettings AddFileLogger(this MSBuildSettings settings, MSBuildFileLogger fileLoggerParameters) + { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + if (fileLoggerParameters == null) + { + throw new ArgumentNullException(nameof(fileLoggerParameters)); + } + settings.FileLoggers.Add(fileLoggerParameters); + + return settings; + } + + /// + /// Adds a file logger with all the default settings. + /// Each file logger will be declared in the order added. + /// The first file logger will match up to the /fl parameter. + /// The next nine (max) file loggers will match up to the /fl1 through /fl9 respectively. + /// + /// The settings. + /// The same instance so that multiple calls can be chained. + public static MSBuildSettings AddFileLogger(this MSBuildSettings settings) + { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + + settings.FileLoggers.Add(new MSBuildFileLogger()); + return settings; + } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/NuGet/Pack/NuGetPackSettings.cs b/src/Cake.Common/Tools/NuGet/Pack/NuGetPackSettings.cs index 67b54f5f89..af09b25434 100644 --- a/src/Cake.Common/Tools/NuGet/Pack/NuGetPackSettings.cs +++ b/src/Cake.Common/Tools/NuGet/Pack/NuGetPackSettings.cs @@ -180,5 +180,14 @@ public sealed class NuGetPackSettings : ToolSettings /// /// The version of MSBuild to be used with this command. public NuGetMSBuildVersion? MSBuildVersion { get; set; } + + /// + /// Gets or sets a value indicating whether the temporarily autogenerated NuSpec file should be kept or not. + /// Defaults to false. + /// + /// + /// true if the temporarily autogenerated NuSpec file should be kept; otherwise false. + /// + public bool KeepTemporaryNuSpecFile { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/NuGet/Pack/NuGetPacker.cs b/src/Cake.Common/Tools/NuGet/Pack/NuGetPacker.cs index 4358e91103..3d20877a91 100644 --- a/src/Cake.Common/Tools/NuGet/Pack/NuGetPacker.cs +++ b/src/Cake.Common/Tools/NuGet/Pack/NuGetPacker.cs @@ -73,7 +73,7 @@ public void Pack(NuGetPackSettings settings) { throw new CakeException("Required setting Description not specified."); } - if (settings.Files == null || settings.Files.Count == 0) + if ((settings.Files == null || settings.Files.Count == 0) && (settings.Dependencies == null || settings.Dependencies.Count == 0)) { throw new CakeException("Required setting Files not specified."); } @@ -124,7 +124,7 @@ private void Pack(NuGetPackSettings settings, Func process) } finally { - if (processedNuspecFilePath != null) + if (processedNuspecFilePath != null && !settings.KeepTemporaryNuSpecFile) { // Delete the processed file. var file = _fileSystem.GetFile(processedNuspecFilePath); diff --git a/src/Cake.Common/Tools/NuGet/Pack/NuSpecDependency.cs b/src/Cake.Common/Tools/NuGet/Pack/NuSpecDependency.cs index c0bf00e22d..2c88d6029a 100644 --- a/src/Cake.Common/Tools/NuGet/Pack/NuSpecDependency.cs +++ b/src/Cake.Common/Tools/NuGet/Pack/NuSpecDependency.cs @@ -20,5 +20,11 @@ public class NuSpecDependency /// /// The dependency's version. public string Version { get; set; } + + /// + /// Gets or sets the dependency's version. + /// + /// The dependency's version. + public string TargetFramework { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/NuGet/Pack/NuspecTransformer.cs b/src/Cake.Common/Tools/NuGet/Pack/NuspecTransformer.cs index b8aa6ebc61..d5db8c2c09 100644 --- a/src/Cake.Common/Tools/NuGet/Pack/NuspecTransformer.cs +++ b/src/Cake.Common/Tools/NuGet/Pack/NuspecTransformer.cs @@ -95,11 +95,31 @@ public static void Transform(XmlDocument document, NuGetPackSettings settings) // Add the files dependenciesElement.RemoveAll(); - foreach (var dependency in settings.Dependencies) + if (settings.Dependencies.All(c => string.IsNullOrEmpty(c.TargetFramework))) { - var fileElement = document.CreateAndAppendElement(dependenciesElement, "dependency"); - fileElement.AddAttributeIfSpecified(dependency.Id, "id"); - fileElement.AddAttributeIfSpecified(dependency.Version, "version"); + foreach (var dependency in settings.Dependencies) + { + var fileElement = document.CreateAndAppendElement(dependenciesElement, "dependency"); + fileElement.AddAttributeIfSpecified(dependency.Id, "id"); + fileElement.AddAttributeIfSpecified(dependency.Version, "version"); + } + } + else + { + foreach (var targetFrameworkDependencies in settings.Dependencies.GroupBy(x => x.TargetFramework)) + { + var groupElement = document.CreateAndAppendElement(dependenciesElement, "group"); + if (!string.IsNullOrEmpty(targetFrameworkDependencies.Key)) + { + groupElement.AddAttributeIfSpecified(targetFrameworkDependencies.Key, "targetFramework"); + } + foreach (var dependency in targetFrameworkDependencies) + { + var fileElement = document.CreateAndAppendElement(groupElement, "dependency"); + fileElement.AddAttributeIfSpecified(dependency.Id, "id"); + fileElement.AddAttributeIfSpecified(dependency.Version, "version"); + } + } } } } diff --git a/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseArgumentBuilder.cs b/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseArgumentBuilder.cs index d0135a2a00..a024383272 100644 --- a/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseArgumentBuilder.cs +++ b/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseArgumentBuilder.cs @@ -2,101 +2,113 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Globalization; using Cake.Core; using Cake.Core.IO; namespace Cake.Common.Tools.OctopusDeploy { - internal class CreateReleaseArgumentBuilder + internal sealed class CreateReleaseArgumentBuilder : OctopusDeployArgumentBuilder { private readonly string _projectName; private readonly CreateReleaseSettings _settings; private readonly ICakeEnvironment _environment; - private readonly ProcessArgumentBuilder _builder; - - public CreateReleaseArgumentBuilder(string projectName, CreateReleaseSettings settings, ICakeEnvironment environment) + public CreateReleaseArgumentBuilder(string projectName, CreateReleaseSettings settings, ICakeEnvironment environment) : base(environment, settings) { _projectName = projectName; _settings = settings; _environment = environment; - _builder = new ProcessArgumentBuilder(); } public ProcessArgumentBuilder Get() - { + { + Builder.Append("create-release"); + Builder.AppendSwitchQuoted("--project", _projectName); + AppendCommonArguments(); AppendArgumentIfNotNull("releaseNumber", _settings.ReleaseNumber); AppendArgumentIfNotNull("defaultpackageversion", _settings.DefaultPackageVersion); - AppendPackages(_settings, _builder); + AppendPackages(_settings, Builder); AppendArgumentIfNotNull("packagesFolder", _settings.PackagesFolder); AppendArgumentIfNotNull("releasenotes", _settings.ReleaseNotes); AppendArgumentIfNotNull("releasenotesfile", _settings.ReleaseNotesFile); + AppendArgumentIfNotNull("channel", _settings.Channel); - if (_settings.IgnoreExisting) + if (_settings.IgnoreChannelRules) { - _builder.Append("--ignoreexisting"); + Builder.Append("--ignorechannelrules"); } - return _builder; - } - - private void AppendCommonArguments() - { - _builder.Append("create-release"); - - _builder.Append("--project"); - _builder.AppendQuoted(_projectName); - - _builder.Append("--server"); - _builder.Append(_settings.Server); - - _builder.Append("--apiKey"); - _builder.AppendSecret(_settings.ApiKey); - - AppendArgumentIfNotNull("username", _settings.Username); - - if (_settings.Password != null) + if (_settings.DeploymentProgress) { - _builder.Append("--password"); - _builder.AppendQuotedSecret(_settings.Password); + Builder.Append("--progress"); } - AppendArgumentIfNotNull("configFile", _settings.ConfigurationFile); - - if (_settings.EnableDebugLogging) + if (_settings.IgnoreExisting) { - _builder.Append("--debug"); + Builder.Append("--ignoreexisting"); } - if (_settings.IgnoreSslErrors) - { - _builder.Append("--ignoreSslErrors"); - } + AppendDeploymnetArguments(); - if (_settings.EnableServiceMessages) - { - _builder.Append("--enableServiceMessages"); - } + return Builder; } - private void AppendArgumentIfNotNull(string argumentName, string value) + private void AppendDeploymnetArguments() { - if (value != null) - { - _builder.Append("--" + argumentName); - _builder.AppendQuoted(value); + AppendArgumentIfNotNull("deployto", _settings.DeployTo); + AppendConditionalFlag(_settings.ShowProgress, "--progress"); + AppendConditionalFlag(_settings.ForcePackageDownload, "--forcepackagedownload"); + AppendConditionalFlag(_settings.WaitForDeployment, "--waitfordeployment"); + + if (_settings.DeploymentTimeout.HasValue) + { + Builder.AppendSwitchQuoted("--deploymenttimeout", "=", _settings.DeploymentTimeout.Value.ToString("hh\\:mm\\:ss")); + } + + AppendConditionalFlag(_settings.CancelOnTimeout, "--cancelontimeout"); + + if (_settings.DeploymentChecksLeepCycle.HasValue) + { + Builder.AppendSwitchQuoted("--deploymentchecksleepcycle", "=", _settings.DeploymentChecksLeepCycle.Value.ToString("hh\\:mm\\:ss")); + } + + if (_settings.GuidedFailure.HasValue) + { + Builder.AppendSwitch("--guidedfailure", "=", _settings.GuidedFailure.ToString()); + } + + if (_settings.SpecificMachines != null && _settings.SpecificMachines.Length > 0) + { + Builder.AppendSwitchQuoted("--specificmachines", "=", string.Join(",", _settings.SpecificMachines)); } - } - private void AppendArgumentIfNotNull(string argumentName, FilePath value) - { - if (value != null) - { - _builder.Append("--" + argumentName); - _builder.AppendQuoted(value.MakeAbsolute(_environment).FullPath); - } + AppendConditionalFlag(_settings.Force, "--force"); + + AppendMultipleTimes("skip", _settings.SkipSteps); + + AppendConditionalFlag(_settings.NoRawLog, "--norawlog"); + + AppendArgumentIfNotNull("rawlogfile", _settings.RawLogFile); + + if (_settings.Variables != null && _settings.Variables.Count > 0) + { + foreach (var pair in _settings.Variables) + { + Builder.AppendSwitchQuoted("--variable", "=", $"{pair.Key}:{pair.Value}"); + } + } + + if (_settings.DeployAt.HasValue) + { + Builder.AppendSwitchQuoted("--deployat", "=", _settings.DeployAt.Value.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture)); + } + + AppendMultipleTimes("tenant", _settings.Tenant); + + AppendMultipleTimes("tenanttag", _settings.TenantTags); } private static void AppendPackages(CreateReleaseSettings settings, ProcessArgumentBuilder builder) @@ -113,6 +125,6 @@ private static void AppendPackages(CreateReleaseSettings settings, ProcessArgume package.Value)); } } - } + } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseSettings.cs b/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseSettings.cs index f89f621fe0..268492005d 100644 --- a/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseSettings.cs +++ b/src/Cake.Common/Tools/OctopusDeploy/CreateReleaseSettings.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using Cake.Core.IO; @@ -9,9 +10,18 @@ namespace Cake.Common.Tools.OctopusDeploy { /// /// Contains settings used by . + /// See Octopus Deploy documentation here /// public sealed class CreateReleaseSettings : OctopusDeploySettings { + /// + /// Initializes a new instance of the class. + /// + public CreateReleaseSettings() + { + Variables = new List>(); + } + /// /// Gets or sets the release number to use for the new release. /// @@ -43,8 +53,109 @@ public sealed class CreateReleaseSettings : OctopusDeploySettings public FilePath ReleaseNotesFile { get; set; } /// - /// Gets or sets a value indicating whether the Ignore Existing flag. + /// Gets or sets a value indicating whether to Ignore Existing release flag. /// public bool IgnoreExisting { get; set; } + + /// + /// Gets or sets environment to automatically deploy to, e.g., Production. + /// + public string DeployTo { get; set; } + + /// + /// Gets or sets a value indicating whether progress of the deployment should be followed. (Sets --waitfordeployment and --norawlog to true.) + /// + public bool ShowProgress { get; set; } + + /// + /// Gets or sets a value indicating whether to force downloading of already installed packages. Default false. + /// + public bool ForcePackageDownload { get; set; } + + /// + /// Gets or sets a value indicating whether to wait synchronously for deployment to finish. + /// + public bool WaitForDeployment { get; set; } + + /// + /// Gets or sets maximum time (timespan format) that the console session will wait for the deployment to finish (default 00:10:00). + /// This will not stop the deployment. Requires WaitForDeployment parameter set. + /// + public TimeSpan? DeploymentTimeout { get; set; } + + /// + /// Gets or sets a value indicating whether to cancel the deployment if the deployment timeout is reached(default false). + /// + public bool CancelOnTimeout { get; set; } + + /// + /// Gets or sets how much time should elapse between deployment status checks(default 00:00:10). + /// + public TimeSpan? DeploymentChecksLeepCycle { get; set; } + + /// + /// Gets or sets a value indicating whether to use Guided Failure mode. If not specified, will use default setting from environment. + /// + public bool? GuidedFailure { get; set; } + + /// + /// Gets or sets list of machines names to target in the deployed environment.If not specified all machines in the environment will be considered. + /// + public string[] SpecificMachines { get; set; } + + /// + /// Gets or sets a value indicating whether a project is configured to skip packages with already-installed versions, override this setting to force re-deployment (flag, default false). + /// + public bool Force { get; set; } + + /// + /// Gets or sets a list of steps to be skipped. Takes step names. + /// + public string[] SkipSteps { get; set; } + + /// + /// Gets or sets a value indicating whether print the raw log of failed tasks or not. + /// + public bool NoRawLog { get; set; } + + /// + /// Gets or sets a file where to redirect the raw log of failed tasks. + /// + public FilePath RawLogFile { get; set; } + + /// + /// Gets or sets values for any prompted variables. + /// + public List> Variables { get; set; } + + /// + /// Gets or sets time at which deployment should start (scheduled deployment), specified as any valid DateTimeOffset format, and assuming the time zone is the current local time zone. + /// + public DateTimeOffset? DeployAt { get; set; } + + /// + /// Gets or sets a tenant the deployment will be performed for; specify this argument multiple times to add multiple tenants or use `*` wildcard to deploy to tenants able to deploy. + /// + public string[] Tenant { get; set; } + + /// + /// Gets or sets a tenant tags used to match tenants that the deployment will be performed for; specify this argument multiple times to add multiple tenant tags. + /// + public string[] TenantTags { get; set; } + + /// + /// Gets or sets the octopus channel for the new release. + /// + public string Channel { get; set; } + + /// + /// Gets or sets a value indicating whether octopus channel rules should be ignored. + /// + public bool IgnoreChannelRules { get; set; } + + /// + /// Gets or sets a value indicating whether progress of the deployment will be shown. + /// + public bool DeploymentProgress { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/OctopusDeploy/DeployReleaseArgumentBuilder.cs b/src/Cake.Common/Tools/OctopusDeploy/DeployReleaseArgumentBuilder.cs new file mode 100644 index 0000000000..a8848e5780 --- /dev/null +++ b/src/Cake.Common/Tools/OctopusDeploy/DeployReleaseArgumentBuilder.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using Cake.Core; +using Cake.Core.IO; + +namespace Cake.Common.Tools.OctopusDeploy +{ + internal sealed class DeployReleaseArgumentBuilder : OctopusDeployArgumentBuilder + { + private readonly ICakeEnvironment _environment; + + private readonly string _projectName; + private readonly string _deployTo; + private readonly string _releaseNumber; + private readonly OctopusDeployReleaseDeploymentSettings _settings; + + public DeployReleaseArgumentBuilder(string server, string apiKey, string projectName, string deployTo, string releaseNumber, OctopusDeployReleaseDeploymentSettings settings, ICakeEnvironment environment) + : base(server, apiKey, environment, settings) + { + _projectName = projectName; + _deployTo = deployTo; + _releaseNumber = releaseNumber; + + _environment = environment; + _settings = settings; + } + + public ProcessArgumentBuilder Get() + { + Builder.Append("deploy-release"); + + Builder.AppendSwitchQuoted("--project", "=", _projectName); + Builder.AppendSwitchQuoted("--deployto", "=", _deployTo); + Builder.AppendSwitchQuoted("--releasenumber", "=", _releaseNumber); + + AppendCommonArguments(); + + AppendDeploymentParameters(); + + return Builder; + } + + private void AppendDeploymentParameters() + { + AppendConditionalFlag(_settings.ShowProgress, "--progress"); + AppendConditionalFlag(_settings.ForcePackageDownload, "--forcepackagedownload"); + AppendConditionalFlag(_settings.WaitForDeployment, "--waitfordeployment"); + + if (_settings.DeploymentTimeout.HasValue) + { + Builder.AppendSwitchQuoted("--deploymenttimeout", "=", + _settings.DeploymentTimeout.Value.ToString("hh\\:mm\\:ss")); + } + + AppendConditionalFlag(_settings.CancelOnTimeout, "--cancelontimeout"); + + if (_settings.DeploymentChecksLeepCycle.HasValue) + { + Builder.AppendSwitchQuoted("--deploymentchecksleepcycle", "=", + _settings.DeploymentChecksLeepCycle.Value.ToString("hh\\:mm\\:ss")); + } + + if (_settings.GuidedFailure.HasValue) + { + Builder.AppendSwitch("--guidedfailure", "=", _settings.GuidedFailure.ToString()); + } + + if (_settings.SpecificMachines != null && _settings.SpecificMachines.Length > 0) + { + Builder.AppendSwitchQuoted("--specificmachines", "=", string.Join(",", _settings.SpecificMachines)); + } + + AppendConditionalFlag(_settings.Force, "--force"); + + AppendMultipleTimes("skip", _settings.SkipSteps); + + AppendConditionalFlag(_settings.NoRawLog, "--norawlog"); + + AppendArgumentIfNotNull("rawlogfile", _settings.RawLogFile); + + if (_settings.Variables != null && _settings.Variables.Count > 0) + { + foreach (var pair in _settings.Variables) + { + Builder.AppendSwitchQuoted("--variable", "=", $"{pair.Key}:{pair.Value}"); + } + } + + if (_settings.DeployAt.HasValue) + { + Builder.AppendSwitchQuoted("--deployat", "=", _settings.DeployAt.Value.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture)); + } + + AppendMultipleTimes("tenant", _settings.Tenant); + + AppendMultipleTimes("tenanttag", _settings.TenantTags); + } + } +} diff --git a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployAliases.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployAliases.cs index f6980959b4..e123150add 100644 --- a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployAliases.cs +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployAliases.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Cake.Common.Tools.MSBuild; using Cake.Core; using Cake.Core.Annotations; using Cake.Core.IO; @@ -87,7 +88,7 @@ public static void OctoCreateRelease(this ICakeContext context, string projectNa /// Pushes the specified package to the Octopus Deploy repository /// /// The cake context - /// /// The Octopus server URL + /// The Octopus server URL /// The user's API key /// Path to the package /// The settings @@ -121,5 +122,87 @@ public static void OctoPush(this ICakeContext context, string server, string api var pusher = new OctopusDeployPusher(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); pusher.PushPackage(server, apiKey, packagePaths.ToArray(), settings); } + + /// + /// Packs the specified folder into an Octopus Deploy package. + /// + /// The cake context + /// The package ID. + [CakeMethodAlias] + public static void OctoPack(this ICakeContext context, string id) + { + OctoPack(context, id, null); + } + + /// + /// Packs the specified folder into an Octopus Deploy package. + /// + /// The cake context + /// The package ID. + /// The settings + [CakeMethodAlias] + public static void OctoPack(this ICakeContext context, string id, OctopusPackSettings settings = null) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + var packer = new OctopusDeployPacker(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); + packer.Pack(id, settings); + } + + /// + /// Deploys the specified already existing release into a specified environment + /// See Octopus Documentation for more details. + /// + /// The cake context + /// The Octopus server URL + /// The user's API key + /// Name of the target project + /// Target environment name + /// Version number of the release to deploy. Specify "latest" for the latest release + /// Deployment settings + /// + /// + /// // bare minimum + /// OctoDeployRelease("http://octopus-deploy.example", "API-XXXXXXXXXXXXXXXXXXXX", "MyGreatProject", "Testing", "2.1.15-RC" new OctopusDeployReleaseDeploymentSettings()); + /// + /// // All of deployment arguments + /// OctoDeployRelease("http://octopus-deploy.example", "API-XXXXXXXXXXXXXXXXXXXX", "MyGreatProject", "Testing", "2.1.15-RC" new OctopusDeployReleaseDeploymentSettings { + /// ShowProgress = true, + /// ForcePackageDownload = true, + /// WaitForDeployment = true, + /// DeploymentTimeout = TimeSpan.FromMinutes(1), + /// CancelOnTimeout = true, + /// DeploymentChecksLeepCycle = TimeSpan.FromMinutes(77), + /// GuidedFailure = true, + /// SpecificMachines = new string[] { "Machine1", "Machine2" }, + /// Force = true, + /// SkipSteps = new[] { "Step1", "Step2" }, + /// NoRawLog = true, + /// RawLogFile = "someFile.txt", + /// DeployAt = new DateTime(2010, 6, 15).AddMinutes(1), + /// Tenant = new[] { "Tenant1", "Tenant2" }, + /// TenantTags = new[] { "Tag1", "Tag2" }, + /// }); + /// + /// + [CakeMethodAlias] + public static void OctoDeployRelease(this ICakeContext context, string server, string apiKey, string projectName, string deployTo, string releaseNumber, OctopusDeployReleaseDeploymentSettings settings) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + var releaseDeployer = new OctopusDeployReleaseDeployer(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); + releaseDeployer.DeployRelease(server, apiKey, projectName, deployTo, releaseNumber, settings); + } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployArgumentBuilder.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployArgumentBuilder.cs index b9b34882d2..427802e6c4 100644 --- a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployArgumentBuilder.cs +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployArgumentBuilder.cs @@ -49,6 +49,26 @@ protected void AppendArgumentIfNotNull(string argumentName, FilePath value) Builder.Append("--" + argumentName); Builder.AppendQuoted(value.MakeAbsolute(Environment).FullPath); } + } + + protected void AppendMultipleTimes(string argumentName, string[] values) + { + if (values != null && values.Length > 0) + { + foreach (var value in values) + { + Builder.AppendSwitchQuoted("--" + argumentName, "=", value); + } + } + } + + protected ProcessArgumentBuilder AppendConditionalFlag(bool condition, string flag) + { + if (condition) + { + Builder.Append(flag); + } + return Builder; } protected void AppendCommonArguments() diff --git a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployPacker.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployPacker.cs new file mode 100644 index 0000000000..ec43dfb67c --- /dev/null +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployPacker.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.OctopusDeploy +{ + /// + /// The Octopus deploy package packer + /// + public sealed class OctopusDeployPacker : Tool + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public OctopusDeployPacker(IFileSystem fileSystem, ICakeEnvironment environment, IProcessRunner processRunner, IToolLocator tools) + : base(fileSystem, environment, processRunner, tools) + { + _environment = environment; + } + + /// + /// Gets the name of the tool. + /// + /// The name of the tool. + protected override string GetToolName() + { + return "Octo"; + } + + /// + /// Gets the possible names of the tool executable. + /// + /// The tool executable name. + protected override IEnumerable GetToolExecutableNames() + { + return new[] { "octo.exe" }; + } + + /// + /// Creates an Octopus deploy package with the specified ID. + /// + /// The package ID. + /// The settings. + public void Pack(string id, OctopusPackSettings settings) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + var arguments = GetArguments(id, settings); + Run(settings, arguments); + } + + private ProcessArgumentBuilder GetArguments(string id, OctopusPackSettings settings) + { + var builder = new ProcessArgumentBuilder(); + + builder.Append("pack"); + builder.Append($"--id {id}"); + + if (!string.IsNullOrWhiteSpace(settings.Version)) + { + builder.AppendSwitch("--version", settings.Version); + } + + if (settings.OutFolder != null) + { + builder.AppendSwitchQuoted("--outFolder", settings.OutFolder.MakeAbsolute(_environment).FullPath); + } + + if (settings.BasePath != null) + { + builder.AppendSwitchQuoted("--basePath", settings.BasePath.MakeAbsolute(_environment).FullPath); + } + + if (!string.IsNullOrWhiteSpace(settings.Author)) + { + builder.AppendSwitchQuoted("--author", settings.Author); + } + + if (!string.IsNullOrWhiteSpace(settings.Title)) + { + builder.AppendSwitchQuoted("--title", settings.Title); + } + + if (!string.IsNullOrWhiteSpace(settings.Description)) + { + builder.AppendSwitchQuoted("--description", settings.Description); + } + + if (!string.IsNullOrWhiteSpace(settings.ReleaseNotes)) + { + builder.AppendSwitchQuoted("--releaseNotes", settings.ReleaseNotes); + } + + if (settings.ReleaseNotesFile != null) + { + builder.AppendSwitchQuoted("--releaseNotesFile", settings.ReleaseNotesFile.MakeAbsolute(_environment).FullPath); + } + + if (settings.Include != null) + { + foreach (var include in settings.Include) + { + builder.AppendSwitchQuoted("--include", include); + } + } + + if (settings.Overwrite) + { + builder.Append("--overwrite"); + } + + return builder; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployReleaseDeployer.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployReleaseDeployer.cs new file mode 100644 index 0000000000..c626667659 --- /dev/null +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployReleaseDeployer.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.OctopusDeploy +{ + /// + /// The Octopus Deploy Release Deploy runner. This class facilitates deploying existing releases in Octopus Deploy. + /// + public sealed class OctopusDeployReleaseDeployer : Tool + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public OctopusDeployReleaseDeployer(IFileSystem fileSystem, ICakeEnvironment environment, IProcessRunner processRunner, IToolLocator tools) + : base(fileSystem, environment, processRunner, tools) + { + _environment = environment; + } + + /// + /// Requests a deployment of a specified release to an environment. + /// + /// Octopus Server URL + /// The user's API key + /// Name of the target project + /// Environment to deploy to, e.g., Production + /// Release number to be deployed to + /// Settings for the deployment + public void DeployRelease(string server, string apiKey, string projectName, string deployTo, string releaseNumber, OctopusDeployReleaseDeploymentSettings settings) + { + if (String.IsNullOrEmpty(server)) + { + throw new ArgumentNullException(nameof(server)); + } + + if (String.IsNullOrEmpty(apiKey)) + { + throw new ArgumentNullException(nameof(apiKey)); + } + + if (String.IsNullOrEmpty(projectName)) + { + throw new ArgumentNullException(nameof(projectName)); + } + + if (String.IsNullOrEmpty(deployTo)) + { + throw new ArgumentNullException(nameof(deployTo)); + } + + if (String.IsNullOrEmpty(releaseNumber)) + { + throw new ArgumentNullException(nameof(releaseNumber)); + } + + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + + var argumentBuilder = new DeployReleaseArgumentBuilder(server, apiKey, projectName, deployTo, releaseNumber, settings, _environment); + Run(settings, argumentBuilder.Get()); + } + + /// + /// Gets the name of the tool. + /// + /// The name of the tool. + protected override string GetToolName() + { + return "Octo"; + } + + /// + /// Gets the possible names of the tool executable. + /// + /// The tool executable name. + protected override IEnumerable GetToolExecutableNames() + { + return new[] { "Octo.exe" }; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployReleaseDeploymentSettings.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployReleaseDeploymentSettings.cs new file mode 100644 index 0000000000..970371a1e1 --- /dev/null +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusDeployReleaseDeploymentSettings.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Cake.Core.IO; + +namespace Cake.Common.Tools.OctopusDeploy +{ + /// + /// Possible arguments to pass to Octo.exe for deploying a release. See Octopus Deploy documentation + /// + public sealed class OctopusDeployReleaseDeploymentSettings : OctopusDeploySettings + { + /// + /// Initializes a new instance of the class. + /// + public OctopusDeployReleaseDeploymentSettings() + { + Variables = new Dictionary(); + } + + /// + /// Gets or sets a value indicating whether progress of the deployment should be followed. (Sets --waitfordeployment and --norawlog to true.) + /// + public bool ShowProgress { get; set; } + + /// + /// Gets or sets a value indicating whether to force downloading of already installed packages. Default false. + /// + public bool ForcePackageDownload { get; set; } + + /// + /// Gets or sets a value indicating whether to wait synchronously for deployment to finish. + /// + public bool WaitForDeployment { get; set; } + + /// + /// Gets or sets maximum time (timespan format) that the console session will wait for the deployment to finish (default 00:10:00). + /// This will not stop the deployment. Requires WaitForDeployment parameter set. + /// + public TimeSpan? DeploymentTimeout { get; set; } + + /// + /// Gets or sets a value indicating whether to cancel the deployment if the deployment timeout is reached(default false). + /// + public bool CancelOnTimeout { get; set; } + + /// + /// Gets or sets how much time should elapse between deployment status checks(default 00:00:10). + /// + public TimeSpan? DeploymentChecksLeepCycle { get; set; } + + /// + /// Gets or sets a value indicating whether to use Guided Failure mode. If not specified, will use default setting from environment. + /// + public bool? GuidedFailure { get; set; } + + /// + /// Gets or sets list of machines names to target in the deployed environment.If not specified all machines in the environment will be considered. + /// + public string[] SpecificMachines { get; set; } + + /// + /// Gets or sets a value indicating whether a project is configured to skip packages with already-installed versions, override this setting to force re-deployment (flag, default false). + /// + public bool Force { get; set; } + + /// + /// Gets or sets a list of steps to be skipped. Takes step names. + /// + public string[] SkipSteps { get; set; } + + /// + /// Gets or sets a value indicating whether print the raw log of failed tasks or not. + /// + public bool NoRawLog { get; set; } + + /// + /// Gets or sets a file where to redirect the raw log of failed tasks. + /// + public FilePath RawLogFile { get; set; } + + /// + /// Gets or sets values for any prompted variables. + /// + public Dictionary Variables { get; set; } + + /// + /// Gets or sets time at which deployment should start (scheduled deployment), specified as any valid DateTimeOffset format, and assuming the time zone is the current local time zone. + /// + public DateTimeOffset? DeployAt { get; set; } + + /// + /// Gets or sets a tenant the deployment will be performed for; specify this argument multiple times to add multiple tenants or use `*` wildcard to deploy to tenants able to deploy. + /// + public string[] Tenant { get; set; } + + /// + /// Gets or sets a tenant tags used to match tenants that the deployment will be performed for; specify this argument multiple times to add multiple tenant tags. + /// + public string[] TenantTags { get; set; } + } +} diff --git a/src/Cake.Common/Tools/VSTest/VSTestLogger.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusPackFormat.cs similarity index 58% rename from src/Cake.Common/Tools/VSTest/VSTestLogger.cs rename to src/Cake.Common/Tools/OctopusDeploy/OctopusPackFormat.cs index d5992cdefd..f8485a4e71 100644 --- a/src/Cake.Common/Tools/VSTest/VSTestLogger.cs +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusPackFormat.cs @@ -1,22 +1,22 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Cake.Common.Tools.VSTest -{ - /// - /// Loggers available for outputting test results. - /// - public enum VSTestLogger - { - /// - /// No logging of test results. - /// - None, - - /// - /// Log results to a Visual Studio test results file. - /// - Trx - } +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Cake.Common.Tools.OctopusDeploy +{ + /// + /// Represents the format of an Octopus package. + /// + public enum OctopusPackFormat + { + /// + /// NuGet package + /// + NuPkg, + + /// + /// Zip package + /// + Zip + } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/OctopusDeploy/OctopusPackSettings.cs b/src/Cake.Common/Tools/OctopusDeploy/OctopusPackSettings.cs new file mode 100644 index 0000000000..25793744f0 --- /dev/null +++ b/src/Cake.Common/Tools/OctopusDeploy/OctopusPackSettings.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.OctopusDeploy +{ + /// + /// Contains the settings used by OctoPack. + /// + public sealed class OctopusPackSettings : ToolSettings + { + /// + /// Gets or sets the version. + /// + public string Version { get; set; } + + /// + /// Gets or sets the package format. + /// + public OctopusPackFormat Format { get; set; } + + /// + /// Gets or sets the folder into which the package will be written. Defaults to the current folder. + /// + public DirectoryPath OutFolder { get; set; } + + /// + /// Gets or sets the root folder containing files and folders to pack. Defaults to the current folder. + /// + public DirectoryPath BasePath { get; set; } + + /// + /// Gets or sets the author. Only applies to NuGet packages. + /// + public string Author { get; set; } + + /// + /// Gets or sets the title. Only applies to NuGet packages. + /// + public string Title { get; set; } + + /// + /// Gets or sets the description. Only applies to NuGet packages. + /// + public string Description { get; set; } + + /// + /// Gets or sets the release notes. Only applies to NuGet packages. + /// + public string ReleaseNotes { get; set; } + + /// + /// Gets or sets the release notes file. Only applies to NuGet packages. + /// + public FilePath ReleaseNotesFile { get; set; } + + /// + /// Gets or sets the file patterns to include. If none are specified, defaults to **. + /// + public ICollection Include { get; set; } + + /// + /// Gets or sets a value indicating whether to allow an existing package with the same ID/version to be overwriten. + /// + public bool Overwrite { get; set; } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/OpenCover/OpenCoverProcessRunner.cs b/src/Cake.Common/Tools/OpenCover/OpenCoverProcessRunner.cs index cf057e8135..178dbeab96 100644 --- a/src/Cake.Common/Tools/OpenCover/OpenCoverProcessRunner.cs +++ b/src/Cake.Common/Tools/OpenCover/OpenCoverProcessRunner.cs @@ -34,6 +34,11 @@ public int GetExitCode() return 0; } + public IEnumerable GetStandardError() + { + return Enumerable.Empty(); + } + public IEnumerable GetStandardOutput() { return Enumerable.Empty(); diff --git a/src/Cake.Common/Tools/Roundhouse/RoundhouseAliases.cs b/src/Cake.Common/Tools/Roundhouse/RoundhouseAliases.cs index f3cfa80077..e6ca9cd76d 100644 --- a/src/Cake.Common/Tools/Roundhouse/RoundhouseAliases.cs +++ b/src/Cake.Common/Tools/Roundhouse/RoundhouseAliases.cs @@ -44,7 +44,7 @@ public static void RoundhouseMigrate(this ICakeContext context, RoundhouseSettin } var runner = new RoundhouseRunner(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); - runner.Run(settings); + runner.Run(settings, settings.Drop); } /// diff --git a/src/Cake.Common/Tools/Roundhouse/RoundhouseRunner.cs b/src/Cake.Common/Tools/Roundhouse/RoundhouseRunner.cs index cb70fcd6d6..1fcd05ea6b 100644 --- a/src/Cake.Common/Tools/Roundhouse/RoundhouseRunner.cs +++ b/src/Cake.Common/Tools/Roundhouse/RoundhouseRunner.cs @@ -81,6 +81,13 @@ private static void AddFlagArguments(ProcessArgumentBuilder builder, RoundhouseS AppendFlag(builder, "dryrun", settings.DryRun); AppendFlag(builder, "restore", settings.Restore); AppendFlag(builder, "silent", settings.Silent); + AppendFlag(builder, "baseline", settings.Baseline); + AppendFlag(builder, "searchallinsteadoftraverse", settings.SearchAllSubdirectoriesInsteadOfTraverse); + AppendFlag(builder, "disabletokens", settings.DisableTokenReplacement); + AppendFlag(builder, "runallanytimescripts", settings.RunAllAnyTimeScripts); + AppendFlag(builder, "debug", settings.Debug); + AppendFlag(builder, "disableoutput", settings.DisableOutput); + AppendFlag(builder, "donotcreatedatabase", settings.DoNotCreateDatabase); AppendFlag(builder, "w", settings.WarnOnOneTimeScriptChanges); AppendFlag(builder, "t", settings.WithTransaction); } diff --git a/src/Cake.Common/Tools/Roundhouse/RoundhouseSettings.cs b/src/Cake.Common/Tools/Roundhouse/RoundhouseSettings.cs index 9aa6f9a25e..78f47548a3 100644 --- a/src/Cake.Common/Tools/Roundhouse/RoundhouseSettings.cs +++ b/src/Cake.Common/Tools/Roundhouse/RoundhouseSettings.cs @@ -199,7 +199,7 @@ public sealed class RoundhouseSettings : ToolSettings /// Gets or sets the schema name to use instead of [RoundhousE]. /// /// - /// The schema where RH stores it's tables. + /// The schema where RH stores its tables. /// public string SchemaName { get; set; } @@ -273,7 +273,7 @@ public sealed class RoundhouseSettings : ToolSettings /// /// This instructs RH to remove a database and not run migration scripts. /// - internal bool Drop { get; set; } + public bool Drop { get; set; } /// /// Gets or sets a value indicating whether to use transactions. @@ -298,5 +298,61 @@ public sealed class RoundhouseSettings : ToolSettings /// This instructs RH to log what would have run, but not to actually run anything against the database. Use this option if you are trying to figure out what RH is going to do. /// public bool DryRun { get; set; } + + /// + /// Gets or sets a value indicating whether to create a database if it does not exist. + /// + /// + /// This instructs RH to not create a database if it does not exists. Defaults to false. + /// + public bool DoNotCreateDatabase { get; set; } + + /// + /// Gets or sets a value indicating whether to disable output of backup, items ran, permissions dumps, etc. + /// + /// + /// Disable output of backups, items ran, permissions dumps, etc. Log files are kept. Useful for example in CI environment. Defaults to false. + /// + public bool DisableOutput { get; set; } + + /// + /// Gets or sets a value indicating whether to create an insert for its recording tables, but not run anything. + /// + /// + /// This instructs RH to create an insert for its recording tables, but not to actually run anything against the database. Use this option if you already have scripts that have been run through other means. Defaults to false. + /// + public bool Baseline { get; set; } + + /// + /// Gets or sets a value indicating whether to write debug messages. + /// + /// + /// This instructs RH to write out all messages. Defaults to false. + /// + public bool Debug { get; set; } + + /// + /// Gets or sets a value indicating whether to execute any time scripts. + /// + /// + /// This instructs RH to run any time scripts every time it is run. Defaults to false. + /// + public bool RunAllAnyTimeScripts { get; set; } + + /// + /// Gets or sets a value indicating whether to perform token replacement. + /// + /// + /// This instructs RH to not perform token replacement {{somename}}. Defaults to false. + /// + public bool DisableTokenReplacement { get; set; } + + /// + /// Gets or sets a value indicating whether to search all subdirectories. + /// + /// + /// Each Migration folder's subdirectories are traversed by default. This option pulls back scripts from the main directory and all subdirectories at once. Defaults to false. + /// + public bool SearchAllSubdirectoriesInsteadOfTraverse { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/SignTool/SignToolDigestAlgorithm.cs b/src/Cake.Common/Tools/SignTool/SignToolDigestAlgorithm.cs new file mode 100644 index 0000000000..e9cf9a78b4 --- /dev/null +++ b/src/Cake.Common/Tools/SignTool/SignToolDigestAlgorithm.cs @@ -0,0 +1,18 @@ +namespace Cake.Common.Tools.SignTool +{ + /// + /// Digest algorithm for SignTool + /// + public enum SignToolDigestAlgorithm + { + /// + /// SHA-1 digest algorithm + /// + Sha1, + + /// + /// SHA-256 digest algorithm. + /// + Sha256 + } +} diff --git a/src/Cake.Common/Tools/SignTool/SignToolSignRunner.cs b/src/Cake.Common/Tools/SignTool/SignToolSignRunner.cs index 685f48fc87..78702e2b5c 100644 --- a/src/Cake.Common/Tools/SignTool/SignToolSignRunner.cs +++ b/src/Cake.Common/Tools/SignTool/SignToolSignRunner.cs @@ -87,7 +87,7 @@ private ProcessArgumentBuilder GetArguments(FilePath assemblyPath, SignToolSignS { if (!_fileSystem.Exist(assemblyPath)) { - const string format = "{0}: The assembly '{1}' do not exist."; + const string format = "{0}: The assembly '{1}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, GetToolName(), assemblyPath.FullPath); throw new CakeException(message); } @@ -104,9 +104,27 @@ private ProcessArgumentBuilder GetArguments(FilePath assemblyPath, SignToolSignS // SIGN Command. builder.Append("SIGN"); + // SHA-256. + if (settings.DigestAlgorithm == SignToolDigestAlgorithm.Sha256) + { + builder.Append("/fd sha256"); + } + // TimeStamp server. - builder.Append("/t"); - builder.AppendQuoted(settings.TimeStampUri.AbsoluteUri); + if (settings.TimeStampDigestAlgorithm == SignToolDigestAlgorithm.Sha256) + { + // If Sha256 use RFC 3161 timestamp server. + builder.Append("/tr"); + builder.AppendQuoted(settings.TimeStampUri.AbsoluteUri); + + builder.Append("/td sha256"); + } + else + { + // Otherwise use SHA-1 Authenticode timestamp server + builder.Append("/t"); + builder.AppendQuoted(settings.TimeStampUri.AbsoluteUri); + } if (settings.CertPath == null && string.IsNullOrEmpty(settings.CertThumbprint)) { @@ -145,7 +163,7 @@ private ProcessArgumentBuilder GetArguments(FilePath assemblyPath, SignToolSignS if (!_fileSystem.Exist(settings.CertPath)) { - const string format = "{0}: The certificate '{1}' do not exist."; + const string format = "{0}: The certificate '{1}' does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, GetToolName(), settings.CertPath.FullPath); throw new CakeException(message); } @@ -180,6 +198,12 @@ private ProcessArgumentBuilder GetArguments(FilePath assemblyPath, SignToolSignS builder.AppendQuoted(settings.DescriptionUri.AbsoluteUri); } + // Append signature. + if (settings.AppendSignature) + { + builder.Append("/as"); + } + // Target Assembly to sign. builder.AppendQuoted(assemblyPath.MakeAbsolute(_environment).FullPath); diff --git a/src/Cake.Common/Tools/SignTool/SignToolSignSettings.cs b/src/Cake.Common/Tools/SignTool/SignToolSignSettings.cs index 6ed2a0347a..af43c9009c 100644 --- a/src/Cake.Common/Tools/SignTool/SignToolSignSettings.cs +++ b/src/Cake.Common/Tools/SignTool/SignToolSignSettings.cs @@ -42,5 +42,20 @@ public sealed class SignToolSignSettings : ToolSettings /// Gets or sets the signed content's expanded description URL. /// public Uri DescriptionUri { get; set; } + + /// + /// Gets or sets the file digest algorithm + /// + public SignToolDigestAlgorithm DigestAlgorithm { get; set; } + + /// + /// Gets or sets the timestamp digest algorithm + /// + public SignToolDigestAlgorithm TimeStampDigestAlgorithm { get; set; } + + /// + /// Gets or sets a value indicating whether the signature should be appended + /// + public bool AppendSignature { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/SpecFlow/SpecFlowProcessRunner.cs b/src/Cake.Common/Tools/SpecFlow/SpecFlowProcessRunner.cs index dc51646870..4ce60c59f0 100644 --- a/src/Cake.Common/Tools/SpecFlow/SpecFlowProcessRunner.cs +++ b/src/Cake.Common/Tools/SpecFlow/SpecFlowProcessRunner.cs @@ -34,6 +34,11 @@ public int GetExitCode() return 0; } + public IEnumerable GetStandardError() + { + return Enumerable.Empty(); + } + public IEnumerable GetStandardOutput() { return Enumerable.Empty(); diff --git a/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReportSettings.cs b/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReportSettings.cs index 8677c764e5..6a53a0ed45 100644 --- a/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReportSettings.cs +++ b/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReportSettings.cs @@ -9,5 +9,10 @@ namespace Cake.Common.Tools.SpecFlow.TestExecutionReport /// public sealed class SpecFlowTestExecutionReportSettings : SpecFlowSettings { + /// + /// Gets or sets a value indicating whether exceptions from the + /// intercepted action should be rethrown after report generation + /// + public bool ThrowOnTestFailure { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporter.cs b/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporter.cs index 8cf750e643..7e57864b21 100644 --- a/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporter.cs +++ b/src/Cake.Common/Tools/SpecFlow/TestExecutionReport/SpecFlowTestExecutionReporter.cs @@ -69,6 +69,7 @@ public void Run(ICakeContext context, var builder = GetArguments(interceptor, settings, projectFile); // Execute the action + CakeException testException = null; try { action(context); @@ -77,10 +78,16 @@ public void Run(ICakeContext context, { // Write warning to log context.Warning(e.Message); + testException = e; } // Run the tool. Run(settings, builder); + + if (settings.ThrowOnTestFailure && testException != null) + { + throw testException; + } } private static SpecFlowContext InterceptAction( diff --git a/src/Cake.Common/Tools/VSTest/VSTestRunner.cs b/src/Cake.Common/Tools/VSTest/VSTestRunner.cs index cc9463e144..54f40ea9b8 100644 --- a/src/Cake.Common/Tools/VSTest/VSTestRunner.cs +++ b/src/Cake.Common/Tools/VSTest/VSTestRunner.cs @@ -54,7 +54,7 @@ public void Run(IEnumerable assemblyPaths, VSTestSettings settings) throw new ArgumentNullException(nameof(settings)); } - base.Run(settings, GetArguments(assemblyPaths, settings)); + Run(settings, GetArguments(assemblyPaths, settings)); } private ProcessArgumentBuilder GetArguments(IEnumerable assemblyPaths, VSTestSettings settings) @@ -64,12 +64,22 @@ private ProcessArgumentBuilder GetArguments(IEnumerable assemblyPaths, // Add the assembly to build. foreach (var assemblyPath in assemblyPaths) { - builder.Append(assemblyPath.MakeAbsolute(_environment).FullPath.Quote()); + builder.AppendQuoted(assemblyPath.MakeAbsolute(_environment).FullPath); } if (settings.SettingsFile != null) { - builder.Append(string.Format(CultureInfo.InvariantCulture, "/Settings:{0}", settings.SettingsFile)); + builder.AppendSwitchQuoted("/Settings", ":", settings.SettingsFile.MakeAbsolute(_environment).FullPath); + } + + if (settings.Parallel) + { + builder.Append("/Parallel"); + } + + if (settings.EnableCodeCoverage) + { + builder.Append("/EnableCodeCoverage"); } if (settings.InIsolation) @@ -77,19 +87,39 @@ private ProcessArgumentBuilder GetArguments(IEnumerable assemblyPaths, builder.Append("/InIsolation"); } + if (settings.UseVsixExtensions != null) + { + builder.AppendSwitch("/UseVsixExtensions", ":", settings.UseVsixExtensions.Value ? "true" : "false"); + } + + if (settings.TestAdapterPath != null) + { + builder.AppendSwitchQuoted("/TestAdapterPath", ":", settings.TestAdapterPath.MakeAbsolute(_environment).FullPath); + } + if (settings.PlatformArchitecture != VSTestPlatform.Default) { - builder.Append(string.Format(CultureInfo.InvariantCulture, "/Platform:{0}", settings.PlatformArchitecture)); + builder.AppendSwitch("/Platform", ":", settings.PlatformArchitecture.ToString()); } if (settings.FrameworkVersion != VSTestFrameworkVersion.Default) { - builder.Append(string.Format(CultureInfo.InvariantCulture, "/Framework:{0}", settings.FrameworkVersion.ToString().Replace("NET", "Framework"))); + builder.AppendSwitch("/Framework", ":", settings.FrameworkVersion.ToString().Replace("NET", "Framework")); + } + + if (settings.TestCaseFilter != null) + { + builder.AppendSwitchQuoted("/TestCaseFilter", ":", settings.TestCaseFilter); + } + + if (settings.Diag != null) + { + builder.AppendSwitchQuoted("/Diag", ":", settings.Diag.MakeAbsolute(_environment).FullPath); } - if (settings.Logger == VSTestLogger.Trx) + if (!string.IsNullOrEmpty(settings.Logger)) { - builder.Append("/Logger:trx"); + builder.Append("/Logger:{0}", settings.Logger.Trim()); } return builder; diff --git a/src/Cake.Common/Tools/VSTest/VSTestSettings.cs b/src/Cake.Common/Tools/VSTest/VSTestSettings.cs index 59c020bac1..acbdfa24a4 100644 --- a/src/Cake.Common/Tools/VSTest/VSTestSettings.cs +++ b/src/Cake.Common/Tools/VSTest/VSTestSettings.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using Cake.Core.IO; using Cake.Core.Tooling; @@ -17,6 +18,16 @@ public sealed class VSTestSettings : ToolSettings /// public FilePath SettingsFile { get; set; } + /// + /// Gets or sets a value indicating whether the tests are executed in parallel. By default up to all available cores on the machine may be used. The number of cores to use may be configured using a settings file. + /// + public bool Parallel { get; set; } + + /// + /// Gets or sets a value indicating whether to enable data diagnostic adapter 'CodeCoverage' in the test run. Default settings are used if not specified using settings file. + /// + public bool EnableCodeCoverage { get; set; } + /// /// Gets or sets a value indicating whether to run tests within the vstest.console.exe process. /// This makes vstest.console.exe process less likely to be stopped on an error in the tests, but tests might run slower. @@ -27,6 +38,16 @@ public sealed class VSTestSettings : ToolSettings /// public bool InIsolation { get; set; } + /// + /// Gets or sets a value overriding whether VSTest will use or skip the VSIX extensions installed (if any) in the test run. + /// + public bool? UseVsixExtensions { get; set; } + + /// + /// Gets or sets a value that makes VSTest use custom test adapters from a given path (if any) in the test run. + /// + public DirectoryPath TestAdapterPath { get; set; } + /// /// Gets or sets the target platform architecture to be used for test execution. /// @@ -38,8 +59,27 @@ public sealed class VSTestSettings : ToolSettings public VSTestFrameworkVersion FrameworkVersion { get; set; } /// - /// Gets or sets the logger to use for test results. + /// Gets or sets an expression to run only tests that match, of the format <property>Operator<value>[|&<Expression>] + /// where Operator is one of =, != or ~ (Operator ~ has 'contains' + /// semantics and is applicable for string properties like DisplayName). + /// Parenthesis () can be used to group sub-expressions. + /// Examples: Priority=1 + /// (FullyQualifiedName~Nightly|Name=MyTestMethod) + /// + public string TestCaseFilter { get; set; } + + /// + /// Gets or sets a path which makes VSTest write diagnosis trace logs to specified file. + /// + public FilePath Diag { get; set; } + + /// + /// Gets or sets the name of your logger. Possible values: + /// - A blank string (or null): no logger + /// - "trx": Visual Studio's built-in logger + /// - "AppVeyor": AppVeyor's custom logger which is available only when building your solution on the AppVeyor platform + /// - any custom value: the name of your custom logger /// - public VSTestLogger Logger { get; set; } + public string Logger { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/VSTest/VSTestSettingsExtensions.cs b/src/Cake.Common/Tools/VSTest/VSTestSettingsExtensions.cs new file mode 100644 index 0000000000..cd0e75a477 --- /dev/null +++ b/src/Cake.Common/Tools/VSTest/VSTestSettingsExtensions.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Cake.Common.Tools.VSTest +{ + /// + /// Contains functionality related to VSTest settings. + /// + public static class VSTestSettingsExtensions + { + /// + /// Do not Log. + /// + /// The settings. + /// The same instance so that multiple calls can be chained. + public static VSTestSettings WithoutAnyLogger(this VSTestSettings settings) + { + return settings.WithLogger(string.Empty); + } + + /// + /// Log to a trx file. + /// + /// The settings. + /// The same instance so that multiple calls can be chained. + public static VSTestSettings WithVisualStudioLogger(this VSTestSettings settings) + { + return settings.WithLogger("trx"); + } + + /// + /// Log to the AppVeyor logger (which is only available when building your solution on the AppVeyor platform). + /// + /// The settings. + /// The same instance so that multiple calls can be chained. + public static VSTestSettings WithAppVeyorLogger(this VSTestSettings settings) + { + return settings.WithLogger("AppVeyor"); + } + + /// + /// Log to a custom logger. + /// + /// The settings. + /// The name of the logger + /// The same instance so that multiple calls can be chained. + public static VSTestSettings WithLogger(this VSTestSettings settings, string loggerName) + { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + settings.Logger = loggerName; + return settings; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/project.json b/src/Cake.Common/project.json index 2ee8f5de29..e252066442 100644 --- a/src/Cake.Common/project.json +++ b/src/Cake.Common/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "description": "Provides aliases (extension methods on Cake context) that support CI, build, unit tests, zip, signing, etc. for Cake.", "copyright": "Copyright (c) .NET Foundation and contributors", "authors": [ diff --git a/src/Cake.Core.Tests/Fixtures/GlobberFixture.cs b/src/Cake.Core.Tests/Fixtures/GlobberFixture.cs index 26b6d1653f..518441b5a9 100644 --- a/src/Cake.Core.Tests/Fixtures/GlobberFixture.cs +++ b/src/Cake.Core.Tests/Fixtures/GlobberFixture.cs @@ -46,6 +46,8 @@ private void PrepareWindowsFixture() FileSystem.CreateFile("C:/Working/Project.IntegrationTest.dll"); FileSystem.CreateFile("C:/Tools & Services/MyTool.dll"); FileSystem.CreateFile("C:/Tools + Services/MyTool.dll"); + FileSystem.CreateFile("C:/Some %2F Directory/MyTool.dll"); + FileSystem.CreateFile("C:/Some ! Directory/MyTool.dll"); } private void PrepareUnixFixture() diff --git a/src/Cake.Core.Tests/Unit/CakeEngineTests.cs b/src/Cake.Core.Tests/Unit/CakeEngineTests.cs index 3f8dd8311f..080e2fbc04 100644 --- a/src/Cake.Core.Tests/Unit/CakeEngineTests.cs +++ b/src/Cake.Core.Tests/Unit/CakeEngineTests.cs @@ -487,7 +487,7 @@ public void Should_Throw_Exception_Thrown_From_Setup_Action_If_Both_Setup_And_Te } [Fact] - public void Should_Throw_Exception_Occuring_In_Teardown_If_No_Previous_Exception_Was_Thrown() + public void Should_Throw_Exception_Occurring_In_Teardown_If_No_Previous_Exception_Was_Thrown() { // Given var fixture = new CakeEngineFixture(); @@ -851,7 +851,7 @@ public void Should_Throw_Exception_Thrown_From_Task_Setup_Action_If_Both_Task_Se } [Fact] - public void Should_Throw_Exception_Occuring_In_Task_Teardown_If_No_Previous_Exception_Was_Thrown() + public void Should_Throw_Exception_Occurring_In_Task_Teardown_If_No_Previous_Exception_Was_Thrown() { // Given var fixture = new CakeEngineFixture(); diff --git a/src/Cake.Core.Tests/Unit/CakeTaskBuilderExtensionsTests.cs b/src/Cake.Core.Tests/Unit/CakeTaskBuilderExtensionsTests.cs index 4580267884..6d8179c887 100644 --- a/src/Cake.Core.Tests/Unit/CakeTaskBuilderExtensionsTests.cs +++ b/src/Cake.Core.Tests/Unit/CakeTaskBuilderExtensionsTests.cs @@ -26,6 +26,71 @@ public void Should_Add_Dependency_To_Task() } } + public sealed class TheIsDependentOnMethodTaskBuilder + { + [Fact] + public void Should_Add_Dependency_To_Task() + { + // Given + var parentTask = new ActionTask("parent"); + var childTask = new ActionTask("child"); + var builder = new CakeTaskBuilder(parentTask); + var cakeTaskBuilder = new CakeTaskBuilder(childTask); + + // When + builder.IsDependentOn(cakeTaskBuilder); + + // Then + Assert.Equal(1, parentTask.Dependencies.Count); + } + + [Fact] + public void Should_Add_Dependency_To_Task_With_Correct_Name() + { + // Given + var parentTask = new ActionTask("parent"); + var childTask = new ActionTask("child"); + var builder = new CakeTaskBuilder(parentTask); + var childTaskBuilder = new CakeTaskBuilder(childTask); + + // When + builder.IsDependentOn(childTaskBuilder); + + // Then + Assert.Equal(parentTask.Dependencies[0], childTaskBuilder.Task.Name); + } + + [Fact] + public void Should_Throw_If_Builder_Is_Null() + { + // Given + var childTask = new ActionTask("child"); + CakeTaskBuilder builder = null; + var childTaskBuilder = new CakeTaskBuilder(childTask); + + // When + var result = Record.Exception(() => builder.IsDependentOn(childTaskBuilder)); + + // Then + Assert.IsArgumentNullException(result, "builder"); + } + + [Fact] + public void Should_Throw_If_OtherBuilder_Is_Null() + { + // Given + var parentTask = new ActionTask("parent"); + var builder = new CakeTaskBuilder(parentTask); + CakeTaskBuilder childTaskBuilder = null; + + // When + var result = Record.Exception(() => builder.IsDependentOn(childTaskBuilder)); + + // Then + Assert.IsArgumentNullException(result, "other"); + } + } + public sealed class TheWithCriteriaMethod { public sealed class ThatAcceptsBoolean diff --git a/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs b/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs index 440a0e3eb6..40dba71e71 100644 --- a/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs +++ b/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs @@ -32,6 +32,30 @@ public void ShouldAppendFormattedTextArgument() Assert.Equal("/arg1:Value1 /arg2:Value2", result); } } + public class ThePrependMethods + { + [Fact] + public void ShouldPrependTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("string arg") + .Prepend("first") + .RenderSafe(); + + Assert.Equal("first string arg", result); + } + + [Fact] + public void ShouldPrependFormattedTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("string arg") + .Prepend("/arg1:{0} /arg2:{1}", "Value1", "Value2") + .RenderSafe(); + + Assert.Equal("/arg1:Value1 /arg2:Value2 string arg", result); + } + } public class TheAppendQuotedMethods { [Fact] @@ -65,6 +89,42 @@ public void ShouldAppendFormattedTextArgument() } } + public class ThePrependQuotedMethods + { + [Fact] + public void ShouldPrependTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependQuoted("string arg") + .RenderSafe(); + + Assert.Equal("\"string arg\" last", result); + } + + [Fact] + public void ShouldPrependProcessArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependQuoted(new TextArgument("text arg")) + .RenderSafe(); + + Assert.Equal("\"text arg\" last", result); + } + + [Fact] + public void ShouldPrependFormattedTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependQuoted("/arg1:{0}", "Value1") + .RenderSafe(); + + Assert.Equal("\"/arg1:Value1\" last", result); + } + } + public class TheAppendSecretMethods { [Fact] @@ -98,6 +158,42 @@ public void ShouldAppendFormattedTextArgument() } } + public class ThePrependSecretMethods + { + [Fact] + public void ShouldPrependTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependSecret("string arg") + .Render(); + + Assert.Equal("string arg last", result); + } + + [Fact] + public void ShouldPrependProcessArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependSecret(new TextArgument("text arg")) + .Render(); + + Assert.Equal("text arg last", result); + } + + [Fact] + public void ShouldPrependFormattedTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependSecret("/arg1:{0}", "Value1") + .Render(); + + Assert.Equal("/arg1:Value1 last", result); + } + } + public class TheAppendQuotedSecretMethods { [Fact] @@ -130,5 +226,41 @@ public void ShouldAppendFormattedTextArgument() Assert.Equal("\"/arg1:Value1 /arg2:Value2\"", result); } } + + public class ThePrependQuotedSecretMethods + { + [Fact] + public void ShouldPrependTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependQuotedSecret("string arg") + .Render(); + + Assert.Equal("\"string arg\" last", result); + } + + [Fact] + public void ShouldPrependProcessArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependQuotedSecret(new TextArgument("text arg")) + .Render(); + + Assert.Equal("\"text arg\" last", result); + } + + [Fact] + public void ShouldPrependFormattedTextArgument() + { + var result = new ProcessArgumentBuilder() + .Append("last") + .PrependQuotedSecret("/arg1:{0} /arg2:{1}", "Value1", "Value2") + .Render(); + + Assert.Equal("\"/arg1:Value1 /arg2:Value2\" last", result); + } + } } } \ No newline at end of file diff --git a/src/Cake.Core.Tests/Unit/Graph/CakeGraphBuilderTests.cs b/src/Cake.Core.Tests/Unit/Graph/CakeGraphBuilderTests.cs index c020bb5760..aa6f49242e 100644 --- a/src/Cake.Core.Tests/Unit/Graph/CakeGraphBuilderTests.cs +++ b/src/Cake.Core.Tests/Unit/Graph/CakeGraphBuilderTests.cs @@ -57,7 +57,7 @@ public void Should_Throw_Exception_When_Depending_On_Task_That_Does_Not_Exist() var result = Assert.Throws(() => CakeGraphBuilder.Build(tasks)); // Then - Assert.Equal("Task 'A' is dependent on task 'C' which do not exist.", result?.Message); + Assert.Equal("Task 'A' is dependent on task 'C' which does not exist.", result?.Message); } } } diff --git a/src/Cake.Core.Tests/Unit/IO/GlobberTests.cs b/src/Cake.Core.Tests/Unit/IO/GlobberTests.cs index c961fe65ae..5eb20ecc3c 100644 --- a/src/Cake.Core.Tests/Unit/IO/GlobberTests.cs +++ b/src/Cake.Core.Tests/Unit/IO/GlobberTests.cs @@ -128,6 +128,34 @@ public void Should_Parse_Glob_Expressions_With_Plus_In_Them() Assert.Equal(1, result.Length); Assert.ContainsFilePath(result, "C:/Tools + Services/MyTool.dll"); } + + [WindowsFact] + public void Should_Parse_Glob_Expressions_With_Percent_In_Them() + { + // Given + var fixture = new GlobberFixture(windows: true); + + // When + var result = fixture.Match("C:/Some %2F Directory/*.dll"); + + // Then + Assert.Equal(1, result.Length); + Assert.ContainsFilePath(result, "C:/Some %2F Directory/MyTool.dll"); + } + + [WindowsFact] + public void Should_Parse_Glob_Expressions_With_Exclamation_In_Them() + { + // Given + var fixture = new GlobberFixture(windows: true); + + // When + var result = fixture.Match("C:/Some ! Directory/*.dll"); + + // Then + Assert.Equal(1, result.Length); + Assert.ContainsFilePath(result, "C:/Some ! Directory/MyTool.dll"); + } } public sealed class WithPredicate diff --git a/src/Cake.Core.Tests/project.json b/src/Cake.Core.Tests/project.json index 28941d31f7..34072f4666 100644 --- a/src/Cake.Core.Tests/project.json +++ b/src/Cake.Core.Tests/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "dependencies": { "dotnet-test-xunit": "2.2.0-preview2-build1029", "Cake.Core": { diff --git a/src/Cake.Core/CakeEngine.cs b/src/Cake.Core/CakeEngine.cs index f39fe627e3..519a4cdcbc 100644 --- a/src/Cake.Core/CakeEngine.cs +++ b/src/Cake.Core/CakeEngine.cs @@ -221,7 +221,7 @@ private void ExecuteTask(ICakeContext context, IExecutionStrategy strategy, Stop } catch (Exception exception) { - _log.Error("An error occured when executing task '{0}'.", task.Name); + _log.Error("An error occurred when executing task '{0}'.", task.Name); exceptionWasThrown = true; @@ -293,7 +293,7 @@ private void PerformTaskTeardown(ICakeContext context, IExecutionStrategy strate } catch (Exception ex) { - _log.Error("An error occured in the custom task teardown action ({0}).", task.Name); + _log.Error("An error occurred in the custom task teardown action ({0}).", task.Name); if (!exceptionWasThrown) { // If no other exception was thrown, we throw this one. @@ -361,7 +361,7 @@ private void PerformTeardown(IExecutionStrategy strategy, ICakeContext context, } catch (Exception ex) { - _log.Error("An error occured in the custom teardown action."); + _log.Error("An error occurred in the custom teardown action."); if (!exceptionWasThrown) { // If no other exception was thrown, we throw this one. diff --git a/src/Cake.Core/CakeEnvironment.cs b/src/Cake.Core/CakeEnvironment.cs index 46c8943fe1..456117ef5b 100644 --- a/src/Cake.Core/CakeEnvironment.cs +++ b/src/Cake.Core/CakeEnvironment.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Versioning; +using Cake.Core.Diagnostics; using Cake.Core.IO; using Cake.Core.Polyfill; @@ -16,6 +17,8 @@ namespace Cake.Core /// public sealed class CakeEnvironment : ICakeEnvironment { + private readonly ICakeLog _log; + /// /// Gets or sets the working directory. /// @@ -49,10 +52,12 @@ public DirectoryPath WorkingDirectory /// /// The platform. /// The runtime. - public CakeEnvironment(ICakePlatform platform, ICakeRuntime runtime) + /// The log. + public CakeEnvironment(ICakePlatform platform, ICakeRuntime runtime, ICakeLog log) { Platform = platform; Runtime = runtime; + _log = log; // Get the application root. var assembly = AssemblyHelper.GetExecutingAssembly(); @@ -95,10 +100,31 @@ public IDictionary GetEnvironmentVariables() { return Environment.GetEnvironmentVariables() .Cast() - .ToDictionary( - key => (string)key.Key, - value => value.Value as string, - StringComparer.OrdinalIgnoreCase); + .Aggregate( + new Dictionary(StringComparer.OrdinalIgnoreCase), + (dictionary, entry) => + { + var key = (string)entry.Key; + var value = entry.Value as string; + string existingValue; + if (dictionary.TryGetValue(key, out existingValue)) + { + if (!StringComparer.OrdinalIgnoreCase.Equals(value, existingValue)) + { + _log.Warning("GetEnvironmentVariables() encountered duplicate for key: {0}, value: {1} (existing value: {2})", + key, + value, + existingValue); + } + } + else + { + dictionary.Add(key, value); + } + + return dictionary; + }, + dictionary => dictionary); } /// diff --git a/src/Cake.Core/CakeTaskBuilderExtensions.cs b/src/Cake.Core/CakeTaskBuilderExtensions.cs index 63e3b4af98..3d20a890e0 100644 --- a/src/Cake.Core/CakeTaskBuilderExtensions.cs +++ b/src/Cake.Core/CakeTaskBuilderExtensions.cs @@ -30,6 +30,32 @@ public static CakeTaskBuilder IsDependentOn(this CakeTaskBuilder builde return builder; } + /// + /// Creates a dependency between two tasks. + /// + /// The task type. + /// The task type that this task depends on. + /// The task builder. + /// The name of the dependent task. + /// The same instance so that multiple calls can be chained. + public static CakeTaskBuilder IsDependentOn(this CakeTaskBuilder builder, CakeTaskBuilder other) + where T : CakeTask + where TOther : CakeTask + { + if (builder == null) + { + throw new ArgumentNullException("builder"); + } + + if (other == null) + { + throw new ArgumentNullException("other"); + } + + builder.Task.AddDependency(other.Task.Name); + return builder; + } + /// /// Adds a criteria that has to be fulfilled for the task to run. /// diff --git a/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs b/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs index ec3758846b..a8ca1bb861 100644 --- a/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs +++ b/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs @@ -27,6 +27,18 @@ public static ProcessArgumentBuilder Append(this ProcessArgumentBuilder builder, return builder; } + /// + /// Prepend the specified text to the argument builder. + /// + /// The builder. + /// The text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder Prepend(this ProcessArgumentBuilder builder, string text) + { + builder?.Prepend(new TextArgument(text)); + return builder; + } + /// /// Formats and appends the specified text to the argument builder. /// @@ -42,6 +54,21 @@ public static ProcessArgumentBuilder Append(this ProcessArgumentBuilder builder, return Append(builder, text); } + /// + /// Formats and prepends the specified text to the argument builder. + /// + /// The builder. + /// A composite format string. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + public static ProcessArgumentBuilder Prepend(this ProcessArgumentBuilder builder, string format, params object[] args) + { + var text = string.Format(CultureInfo.InvariantCulture, format, args); + return Prepend(builder, text); + } + /// /// Quotes and appends the specified text to the argument builder. /// @@ -54,6 +81,18 @@ public static ProcessArgumentBuilder AppendQuoted(this ProcessArgumentBuilder bu return builder; } + /// + /// Quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// The text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuoted(this ProcessArgumentBuilder builder, string text) + { + builder?.Prepend(new QuotedArgument(new TextArgument(text))); + return builder; + } + /// /// Formats, quotes and appends the specified text to the argument builder. /// @@ -69,6 +108,21 @@ public static ProcessArgumentBuilder AppendQuoted(this ProcessArgumentBuilder bu return AppendQuoted(builder, text); } + /// + /// Formats, quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// A composite format string to be quoted and prepended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + public static ProcessArgumentBuilder PrependQuoted(this ProcessArgumentBuilder builder, string format, params object[] args) + { + var text = string.Format(CultureInfo.InvariantCulture, format, args); + return PrependQuoted(builder, text); + } + /// /// Quotes and appends the specified argument to the argument builder. /// @@ -81,6 +135,18 @@ public static ProcessArgumentBuilder AppendQuoted(this ProcessArgumentBuilder bu return builder; } + /// + /// Quotes and prepends the specified argument to the argument builder. + /// + /// The builder. + /// The argument to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuoted(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.Prepend(new QuotedArgument(argument)); + return builder; + } + /// /// Appends the specified secret text to the argument builder. /// @@ -93,6 +159,18 @@ public static ProcessArgumentBuilder AppendSecret(this ProcessArgumentBuilder bu return builder; } + /// + /// Prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSecret(this ProcessArgumentBuilder builder, string text) + { + builder?.Prepend(new SecretArgument(new TextArgument(text))); + return builder; + } + /// /// Formats and appends the specified secret text to the argument builder. /// @@ -109,6 +187,22 @@ public static ProcessArgumentBuilder AppendSecret(this ProcessArgumentBuilder bu return AppendSecret(builder, text); } + /// + /// Formats and prepend the specified secret text to the argument builder. + /// + /// The builder. + /// A composite format string for the secret text to be prepended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSecret(this ProcessArgumentBuilder builder, string format, params object[] args) + { + var text = string.Format(CultureInfo.InvariantCulture, format, args); + return PrependSecret(builder, text); + } + /// /// Appends the specified secret text to the argument builder. /// @@ -121,6 +215,18 @@ public static ProcessArgumentBuilder AppendSecret(this ProcessArgumentBuilder bu return builder; } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.Prepend(new SecretArgument(argument)); + return builder; + } + /// /// Quotes and appends the specified secret text to the argument builder. /// @@ -133,6 +239,18 @@ public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuil return builder; } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string text) + { + builder?.PrependQuoted(new SecretArgument(new TextArgument(text))); + return builder; + } + /// /// Formats, quotes and appends the specified secret text to the argument builder. /// @@ -149,6 +267,22 @@ public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuil return AppendQuotedSecret(builder, text); } + /// + /// Formats, quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// A composite format string for the secret text to be quoted and prepended. + /// An object array that contains zero or more objects to format. + /// The same instance so that multiple calls can be chained. + /// or is null. + /// is invalid.-or- The index of a format item is less than zero, or greater than or equal to the length of the array. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string format, params object[] args) + { + var text = string.Format(CultureInfo.InvariantCulture, format, args); + return PrependQuotedSecret(builder, text); + } + /// /// Quotes and appends the specified secret text to the argument builder. /// @@ -161,6 +295,18 @@ public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuil return builder; } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, IProcessArgument argument) + { + builder?.PrependQuoted(new SecretArgument(argument)); + return builder; + } + /// /// Appends the specified switch to the argument builder. /// @@ -173,6 +319,18 @@ public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder bu return AppendSwitch(builder, @switch, " ", text); } + /// + /// Prepend the specified switch to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitch(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitch(builder, @switch, " ", text); + } + /// /// Appends the specified switch to the argument builder. /// @@ -187,6 +345,20 @@ public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder bu return builder; } + /// + /// Prepend the specified switch to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitch(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Prepend(new SwitchArgument(@switch, new TextArgument(text), separator)); + return builder; + } + /// /// Quotes and appends the specified text to the argument builder. /// @@ -199,6 +371,18 @@ public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuil return AppendSwitchQuoted(builder, @switch, " ", text); } + /// + /// Quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitchQuoted(builder, @switch, " ", text); + } + /// /// Quotes and appends the specified text to the argument builder. /// @@ -213,6 +397,20 @@ public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuil return builder; } + /// + /// Quotes and prepends the specified text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Prepend(new SwitchArgument(@switch, new QuotedArgument(new TextArgument(text)), separator)); + return builder; + } + /// /// Quotes and appends the specified argument to the argument builder. /// @@ -225,6 +423,18 @@ public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuil return AppendSwitchQuoted(builder, @switch, " ", argument); } + /// + /// Quotes and prepends the specified argument to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The argument to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return PrependSwitchQuoted(builder, @switch, " ", argument); + } + /// /// Quotes and appends the specified argument to the argument builder. /// @@ -239,6 +449,20 @@ public static ProcessArgumentBuilder AppendSwitchQuoted(this ProcessArgumentBuil return builder; } + /// + /// Quotes and prepends the specified argument to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The argument to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuoted(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.Prepend(new SwitchArgument(@switch, new QuotedArgument(argument), separator)); + return builder; + } + /// /// Appends the specified secret text to the argument builder. /// @@ -251,6 +475,18 @@ public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuil return AppendSwitchSecret(builder, @switch, " ", text); } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitchSecret(builder, @switch, " ", text); + } + /// /// Appends the specified secret text to the argument builder. /// @@ -265,6 +501,20 @@ public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuil return builder; } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret text to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.Prepend(new SwitchArgument(@switch, new SecretArgument(new TextArgument(text)), separator)); + return builder; + } + /// /// Appends the specified secret text to the argument builder. /// @@ -277,6 +527,18 @@ public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuil return AppendSwitchSecret(builder, @switch, " ", argument); } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return PrependSwitchSecret(builder, @switch, " ", argument); + } + /// /// Appends the specified secret text to the argument builder. /// @@ -291,6 +553,20 @@ public static ProcessArgumentBuilder AppendSwitchSecret(this ProcessArgumentBuil return builder; } + /// + /// Prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.Prepend(new SwitchArgument(@switch, new SecretArgument(argument), separator)); + return builder; + } + /// /// Quotes and appends the specified secret text to the argument builder. /// @@ -303,6 +579,18 @@ public static ProcessArgumentBuilder AppendSwitchQuotedSecret(this ProcessArgume return AppendSwitchQuotedSecret(builder, @switch, " ", text); } + /// + /// Quotes and prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string text) + { + return PrependSwitchQuotedSecret(builder, @switch, " ", text); + } + /// /// Quotes and appends the specified secret text to the argument builder. /// @@ -317,6 +605,20 @@ public static ProcessArgumentBuilder AppendSwitchQuotedSecret(this ProcessArgume return builder; } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument. + /// The secret text to be quoted and prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependSwitchQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, string text) + { + builder?.PrependSwitchQuoted(@switch, separator, new SecretArgument(new TextArgument(text))); + return builder; + } + /// /// Quotes and appends the specified secret text to the argument builder. /// @@ -329,6 +631,18 @@ public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuil return AppendQuotedSecret(builder, @switch, " ", argument); } + /// + /// Quotes and prepends the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string @switch, IProcessArgument argument) + { + return PrependQuotedSecret(builder, @switch, " ", argument); + } + /// /// Quotes and appends the specified secret text to the argument builder. /// @@ -343,6 +657,20 @@ public static ProcessArgumentBuilder AppendQuotedSecret(this ProcessArgumentBuil return builder; } + /// + /// Quotes and prepend the specified secret text to the argument builder. + /// + /// The builder. + /// The switch preceding the text. + /// The separator between the switch and argument + /// The secret argument to be prepended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder PrependQuotedSecret(this ProcessArgumentBuilder builder, string @switch, string separator, IProcessArgument argument) + { + builder?.PrependSwitchQuoted(@switch, separator, new SecretArgument(argument)); + return builder; + } + /// /// Indicates whether a is null or renders empty. /// diff --git a/src/Cake.Core/Graph/CakeGraphBuilder.cs b/src/Cake.Core/Graph/CakeGraphBuilder.cs index 273922cb13..1cd04a8dfc 100644 --- a/src/Cake.Core/Graph/CakeGraphBuilder.cs +++ b/src/Cake.Core/Graph/CakeGraphBuilder.cs @@ -22,7 +22,7 @@ public static CakeGraph Build(List tasks) { if (!graph.Exist(dependency)) { - const string format = "Task '{0}' is dependent on task '{1}' which do not exist."; + const string format = "Task '{0}' is dependent on task '{1}' which does not exist."; var message = string.Format(CultureInfo.InvariantCulture, format, task.Name, dependency); throw new CakeException(message); } diff --git a/src/Cake.Core/IO/Directory.cs b/src/Cake.Core/IO/Directory.cs index afc85be431..e8f367ca04 100644 --- a/src/Cake.Core/IO/Directory.cs +++ b/src/Cake.Core/IO/Directory.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -31,6 +32,15 @@ public void Create() _directory.Create(); } + public void Move(DirectoryPath destination) + { + if (destination == null) + { + throw new ArgumentNullException(nameof(destination)); + } + _directory.MoveTo(destination.FullPath); + } + public void Delete(bool recursive) { _directory.Delete(recursive); diff --git a/src/Cake.Core/IO/FilePath.cs b/src/Cake.Core/IO/FilePath.cs index 93f369d6e6..fa6a3d2534 100644 --- a/src/Cake.Core/IO/FilePath.cs +++ b/src/Cake.Core/IO/FilePath.cs @@ -53,9 +53,9 @@ public FilePath GetFilename() } /// - /// Gets the filename without it's extension. + /// Gets the filename without its extension. /// - /// The filename without it's extension. + /// The filename without its extension. public FilePath GetFilenameWithoutExtension() { var filename = System.IO.Path.GetFileNameWithoutExtension(FullPath); diff --git a/src/Cake.Core/IO/Globbing/GlobTokenizer.cs b/src/Cake.Core/IO/Globbing/GlobTokenizer.cs index bd52f00b9b..e41d31c808 100644 --- a/src/Cake.Core/IO/Globbing/GlobTokenizer.cs +++ b/src/Cake.Core/IO/Globbing/GlobTokenizer.cs @@ -27,7 +27,7 @@ public GlobTokenizer(string pattern) _sourceIndex = 0; _currentContent = string.Empty; _currentCharacter = _pattern[_sourceIndex]; - _identifierRegex = new Regex("^[0-9a-zA-Z\\+&(). _-]$", RegexOptions.Compiled); + _identifierRegex = new Regex("^[0-9a-zA-Z\\+&%!(). _-]$", RegexOptions.Compiled); } public GlobToken Scan() diff --git a/src/Cake.Core/IO/IDirectory.cs b/src/Cake.Core/IO/IDirectory.cs index 2ee1579f21..8dac878832 100644 --- a/src/Cake.Core/IO/IDirectory.cs +++ b/src/Cake.Core/IO/IDirectory.cs @@ -22,6 +22,12 @@ public interface IDirectory : IFileSystemInfo /// void Create(); + /// + /// Moves the directory to the specified destination path. + /// + /// The destination path. + void Move(DirectoryPath destination); + /// /// Deletes the directory. /// diff --git a/src/Cake.Core/IO/IProcess.cs b/src/Cake.Core/IO/IProcess.cs index 5594ff6da7..3831e4fbd5 100644 --- a/src/Cake.Core/IO/IProcess.cs +++ b/src/Cake.Core/IO/IProcess.cs @@ -30,6 +30,12 @@ public interface IProcess : IDisposable /// The exit code of the process. int GetExitCode(); + /// + /// Get the standard error of process. + /// + /// Returns process error output RedirectStandardError is true + IEnumerable GetStandardError(); + /// /// Get the standard output of process /// diff --git a/src/Cake.Core/IO/ProcessArgumentBuilder.cs b/src/Cake.Core/IO/ProcessArgumentBuilder.cs index fe02677f64..f6434a4855 100644 --- a/src/Cake.Core/IO/ProcessArgumentBuilder.cs +++ b/src/Cake.Core/IO/ProcessArgumentBuilder.cs @@ -47,6 +47,15 @@ public void Append(IProcessArgument argument) _tokens.Add(argument); } + /// + /// Prepends an argument. + /// + /// The argument. + public void Prepend(IProcessArgument argument) + { + _tokens.Insert(0, argument); + } + /// /// Renders the arguments as a . /// Sensitive information will be included. diff --git a/src/Cake.Core/IO/ProcessRunner.cs b/src/Cake.Core/IO/ProcessRunner.cs index 36102d3ebd..92c8797316 100644 --- a/src/Cake.Core/IO/ProcessRunner.cs +++ b/src/Cake.Core/IO/ProcessRunner.cs @@ -103,7 +103,25 @@ public IProcess Start(FilePath filePath, ProcessSettings settings) ? SubscribeStandardConsoleOutputQueue(process) : null; - return new ProcessWrapper(process, _log, arguments.FilterUnsafe, consoleOutputQueue); + var consoleErrorQueue = settings.RedirectStandardError + ? SubscribeStandardConsoleErrorQueue(process) + : null; + + return new ProcessWrapper(process, _log, arguments.FilterUnsafe, consoleOutputQueue, arguments.FilterUnsafe, consoleErrorQueue); + } + + private static ConcurrentQueue SubscribeStandardConsoleErrorQueue(Process process) + { + var consoleErrorQueue = new ConcurrentQueue(); + process.ErrorDataReceived += (s, e) => + { + if (e.Data != null) + { + consoleErrorQueue.Enqueue(e.Data); + } + }; + process.BeginErrorReadLine(); + return consoleErrorQueue; } private static ConcurrentQueue SubscribeStandardConsoleOutputQueue(Process process) diff --git a/src/Cake.Core/IO/ProcessSettings.cs b/src/Cake.Core/IO/ProcessSettings.cs index 13ec206278..defa795095 100644 --- a/src/Cake.Core/IO/ProcessSettings.cs +++ b/src/Cake.Core/IO/ProcessSettings.cs @@ -23,6 +23,12 @@ public sealed class ProcessSettings /// The working directory for the process to be started. public DirectoryPath WorkingDirectory { get; set; } + /// + /// Gets or sets a value indicating whether the error output of an application is written to the stream. + /// + /// true if error output should be written to ; otherwise, false. The default is false. + public bool RedirectStandardError { get; set; } + /// /// Gets or sets a value indicating whether the output of an application is written to the stream. /// diff --git a/src/Cake.Core/IO/ProcessWrapper.cs b/src/Cake.Core/IO/ProcessWrapper.cs index ad0d328ac4..b689db9a90 100644 --- a/src/Cake.Core/IO/ProcessWrapper.cs +++ b/src/Cake.Core/IO/ProcessWrapper.cs @@ -14,15 +14,19 @@ internal sealed class ProcessWrapper : IProcess { private readonly Process _process; private readonly ICakeLog _log; + private readonly Func _filterError; private readonly Func _filterOutput; + private readonly ConcurrentQueue _consoleErrorQueue; private readonly ConcurrentQueue _consoleOutputQueue; - public ProcessWrapper(Process process, ICakeLog log, Func filterOutput, ConcurrentQueue consoleOutputQueue) + public ProcessWrapper(Process process, ICakeLog log, Func filterOutput, ConcurrentQueue consoleOutputQueue, Func filterError, ConcurrentQueue consoleErrorQueue) { _process = process; _log = log; _filterOutput = filterOutput ?? (source => "[REDACTED]"); _consoleOutputQueue = consoleOutputQueue; + _filterError = filterError ?? (source => "[REDACTED]"); + _consoleErrorQueue = consoleErrorQueue; } public void WaitForExit() @@ -49,6 +53,24 @@ public int GetExitCode() return _process.ExitCode; } + public IEnumerable GetStandardError() + { + if (_consoleErrorQueue == null) + { + yield break; + } + while (!_consoleErrorQueue.IsEmpty || !_process.HasExited) + { + string line; + if (!_consoleErrorQueue.TryDequeue(out line)) + { + continue; + } + _log.Debug(log => log("{0}", _filterOutput(line))); + yield return line; + } + } + public IEnumerable GetStandardOutput() { if (_consoleOutputQueue == null) diff --git a/src/Cake.Core/Polyfill/ProcessHelper.cs b/src/Cake.Core/Polyfill/ProcessHelper.cs index 5d3a0cbedd..2679fcbabf 100644 --- a/src/Cake.Core/Polyfill/ProcessHelper.cs +++ b/src/Cake.Core/Polyfill/ProcessHelper.cs @@ -1,4 +1,6 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; +using System.Linq; namespace Cake.Core.Polyfill { @@ -7,8 +9,10 @@ internal static class ProcessHelper public static void SetEnvironmentVariable(ProcessStartInfo info, string key, string value) { #if NETCORE - info.Environment[key] = value; + var envKey = info.Environment.Keys.FirstOrDefault(exisitingKey => StringComparer.OrdinalIgnoreCase.Equals(exisitingKey, key)) ?? key; + info.Environment[envKey] = value; #else + var envKey = info.EnvironmentVariables.Keys.Cast().FirstOrDefault(existingKey => StringComparer.OrdinalIgnoreCase.Equals(existingKey, key)) ?? key; info.EnvironmentVariables[key] = value; #endif } diff --git a/src/Cake.Core/Properties/AssemblyInfo.cs b/src/Cake.Core/Properties/AssemblyInfo.cs index 039d83bb80..f9b7bad46f 100644 --- a/src/Cake.Core/Properties/AssemblyInfo.cs +++ b/src/Cake.Core/Properties/AssemblyInfo.cs @@ -21,6 +21,7 @@ // We're CLS compliant. [assembly: CLSCompliant(true)] -// Make internals visible to unit test assembly. +// Make internals visible to other Cake assemblies. +[assembly: InternalsVisibleTo("Cake.Common")] [assembly: InternalsVisibleTo("Cake.Core.Tests")] [assembly: InternalsVisibleTo("Cake.Testing.Xunit")] \ No newline at end of file diff --git a/src/Cake.Core/Reflection/AssemblyLoader.cs b/src/Cake.Core/Reflection/AssemblyLoader.cs index 0626234b04..e530d79063 100644 --- a/src/Cake.Core/Reflection/AssemblyLoader.cs +++ b/src/Cake.Core/Reflection/AssemblyLoader.cs @@ -37,7 +37,7 @@ public Assembly Load(FilePath path) if (path.Segments.Length == 1 && !_fileSystem.Exist(path)) { - // Not a valid path. Try loading it by it's name. + // Not a valid path. Try loading it by its name. return Assembly.Load(new AssemblyName(path.FullPath)); } diff --git a/src/Cake.Core/Reflection/IAssemblyLoader.cs b/src/Cake.Core/Reflection/IAssemblyLoader.cs index 626ce75565..871e56722e 100644 --- a/src/Cake.Core/Reflection/IAssemblyLoader.cs +++ b/src/Cake.Core/Reflection/IAssemblyLoader.cs @@ -13,7 +13,7 @@ namespace Cake.Core.Reflection public interface IAssemblyLoader { /// - /// Loads the specified assembly from it's assembly name. + /// Loads the specified assembly from its assembly name. /// /// The assembly name. /// The loaded assembly. diff --git a/src/Cake.Core/Scripting/ScriptAliasFinder.cs b/src/Cake.Core/Scripting/ScriptAliasFinder.cs index 0510771590..2d9faaccd1 100644 --- a/src/Cake.Core/Scripting/ScriptAliasFinder.cs +++ b/src/Cake.Core/Scripting/ScriptAliasFinder.cs @@ -128,7 +128,7 @@ private ScriptAlias CreateAlias(Tuple alias) catch (Exception ex) { // Log this error. - const string format = "An error occured while generating code for alias {0}."; + const string format = "An error occurred while generating code for alias {0}."; _log.Error(format, method.GetSignature(false)); _log.Error("Error: {0}", ex.Message); } diff --git a/src/Cake.Core/Tooling/ToolResolutionStrategy.cs b/src/Cake.Core/Tooling/ToolResolutionStrategy.cs index 49c75fcbaf..380d7c4158 100644 --- a/src/Cake.Core/Tooling/ToolResolutionStrategy.cs +++ b/src/Cake.Core/Tooling/ToolResolutionStrategy.cs @@ -147,7 +147,16 @@ private List GetPathDirectories() { var separator = new[] { _environment.Platform.IsUnix() ? ':' : ';' }; var paths = path.Split(separator, StringSplitOptions.RemoveEmptyEntries); - result.AddRange(paths.Select(p => new DirectoryPath(p))); + foreach (var p in paths) + { + try + { + result.Add(new DirectoryPath(p.Trim(' ', '"', '\''))); + } + catch + { + } + } } return result; diff --git a/src/Cake.Core/project.json b/src/Cake.Core/project.json index 2fc36c881d..b18a2090c6 100644 --- a/src/Cake.Core/project.json +++ b/src/Cake.Core/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "description": "The Cake core library.", "copyright": "Copyright (c) .NET Foundation and contributors", "authors": [ diff --git a/src/Cake.NuGet.Tests/project.json b/src/Cake.NuGet.Tests/project.json index 7e8a1673e0..54b3f63a18 100644 --- a/src/Cake.NuGet.Tests/project.json +++ b/src/Cake.NuGet.Tests/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "buildOptions": { "platform": "AnyCpu", "additionalArguments": [ diff --git a/src/Cake.NuGet/project.json b/src/Cake.NuGet/project.json index afb9bb8b9a..02d5b0f21a 100644 --- a/src/Cake.NuGet/project.json +++ b/src/Cake.NuGet/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "dependencies": { "Cake.Core": { "target": "project" diff --git a/src/Cake.Testing.Xunit/project.json b/src/Cake.Testing.Xunit/project.json index 4b76a7f038..57473e9a01 100644 --- a/src/Cake.Testing.Xunit/project.json +++ b/src/Cake.Testing.Xunit/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "configurations": { "Release": { "buildOptions": { diff --git a/src/Cake.Testing/Extensions/FakeFileSystemExtensions.cs b/src/Cake.Testing/Extensions/FakeFileSystemExtensions.cs index 20b990c853..18283e071b 100644 --- a/src/Cake.Testing/Extensions/FakeFileSystemExtensions.cs +++ b/src/Cake.Testing/Extensions/FakeFileSystemExtensions.cs @@ -15,11 +15,11 @@ namespace Cake.Testing public static class FakeFileSystemExtensions { /// - /// Ensures that the specified file do not exist. + /// Ensures that the specified file does not exist. /// /// The file system. /// The path. - public static void EnsureFileDoNotExist(this FakeFileSystem fileSystem, FilePath path) + public static void EnsureFileDoesNotExist(this FakeFileSystem fileSystem, FilePath path) { if (fileSystem == null) { diff --git a/src/Cake.Testing/Extensions/ToolFixtureExtensions.cs b/src/Cake.Testing/Extensions/ToolFixtureExtensions.cs index 3ce2b274e2..9259d85415 100644 --- a/src/Cake.Testing/Extensions/ToolFixtureExtensions.cs +++ b/src/Cake.Testing/Extensions/ToolFixtureExtensions.cs @@ -15,7 +15,7 @@ namespace Cake.Testing public static class ToolFixtureExtensions { /// - /// Ensures that the tool do not exist under the tool settings tool path. + /// Ensures that the tool does not exist under the tool settings tool path. /// /// The type of the tool settings. /// The type of the fixture result. diff --git a/src/Cake.Testing/FakeDirectory.cs b/src/Cake.Testing/FakeDirectory.cs index 99be097d47..e3aa4645e7 100644 --- a/src/Cake.Testing/FakeDirectory.cs +++ b/src/Cake.Testing/FakeDirectory.cs @@ -64,6 +64,15 @@ public void Create() _tree.CreateDirectory(this); } + /// + /// Moves the directory to the specified destination path. + /// + /// The destination path. + public void Move(DirectoryPath destination) + { + _tree.MoveDirectory(this, destination); + } + /// /// Deletes the directory. /// diff --git a/src/Cake.Testing/FakeFileSystemTree.cs b/src/Cake.Testing/FakeFileSystemTree.cs index f0d5ebb572..a260d62252 100644 --- a/src/Cake.Testing/FakeFileSystemTree.cs +++ b/src/Cake.Testing/FakeFileSystemTree.cs @@ -218,7 +218,7 @@ public void CopyFile(FakeFile file, FilePath destination, bool overwrite) { if (!file.Exists) { - throw new FileNotFoundException("File do not exist."); + throw new FileNotFoundException("File does not exist."); } // Already exists? @@ -237,7 +237,7 @@ public void CopyFile(FakeFile file, FilePath destination, bool overwrite) var directory = FindDirectory(destination.GetDirectory()); if (directory == null || !directory.Exists) { - throw new DirectoryNotFoundException("The destination path {0} do not exist."); + throw new DirectoryNotFoundException("The destination path {0} does not exist."); } // Make sure the file exist. @@ -262,5 +262,73 @@ public void MoveFile(FakeFile fakeFile, FilePath destination) // Delete the original file. fakeFile.Delete(); } + + public void MoveDirectory(FakeDirectory fakeDirectory, DirectoryPath destination) + { + var root = new Stack(); + var result = new Stack(); + + if (string.IsNullOrEmpty(destination.FullPath)) + { + throw new ArgumentException("The destination directory is empty."); + } + + if (fakeDirectory.Path.Equals(destination)) + { + throw new IOException("The directory being moved and the destination directory have the same name."); + } + + if (FindDirectory(destination) != null) + { + throw new IOException("The destination directory already exists."); + } + + string destinationParentPathStr = string.Join("/", destination.Segments.Take(destination.Segments.Length - 1).DefaultIfEmpty("/")); + DirectoryPath destinationParentPath = new DirectoryPath(destinationParentPathStr == string.Empty ? "/" : destinationParentPathStr); + if (FindDirectory(destinationParentPath) == null) + { + throw new DirectoryNotFoundException("The parent destination directory " + destinationParentPath.FullPath + " could not be found."); + } + + if (fakeDirectory.Exists) + { + root.Push(fakeDirectory); + } + + // Create destination directories and move files + while (root.Count > 0) + { + var node = root.Pop(); + result.Push(node); + + // Create destination directory + DirectoryPath relativePath = fakeDirectory.Path.GetRelativePath(node.Path); + DirectoryPath destinationPath = destination.Combine(relativePath); + CreateDirectory(destinationPath); + + var files = node.Content.Files.Select(x => x).ToArray(); + foreach (var file in files) + { + // Move the file. + MoveFile(file.Value, destinationPath.CombineWithFilePath(file.Key.GetFilename())); + } + + var directories = node.Content.Directories; + foreach (var child in directories) + { + root.Push(child.Value); + } + } + + // Delete source directories + while (result.Count > 0) + { + var directory = result.Pop(); + + // Delete the directory. + directory.Parent.Content.Remove(directory); + directory.Exists = false; + } + } } } \ No newline at end of file diff --git a/src/Cake.Testing/FakeProcess.cs b/src/Cake.Testing/FakeProcess.cs index eaad028c47..356a25a26c 100644 --- a/src/Cake.Testing/FakeProcess.cs +++ b/src/Cake.Testing/FakeProcess.cs @@ -13,6 +13,7 @@ namespace Cake.Testing public sealed class FakeProcess : IProcess { private int _exitCode; + private IEnumerable _standardError; private IEnumerable _standardOutput; /// @@ -48,6 +49,15 @@ public int GetExitCode() return _exitCode; } + /// + /// Get the standard error of process + /// + /// Returns process error output RedirectStandardError is true + public IEnumerable GetStandardError() + { + return _standardError; + } + /// /// Get the standard output of process /// @@ -73,6 +83,15 @@ public void SetExitCode(int exitCode) _exitCode = exitCode; } + /// + /// Sets the standard error. + /// + /// The standard error. + public void SetStandardError(IEnumerable standardError) + { + _standardError = standardError; + } + /// /// Sets the standard output. /// diff --git a/src/Cake.Testing/project.json b/src/Cake.Testing/project.json index c39dfae5d6..ad99d57a51 100644 --- a/src/Cake.Testing/project.json +++ b/src/Cake.Testing/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "description": "Contains testing utilities for Cake.", "copyright": "Copyright (c) .NET Foundation and contributors", "authors": [ diff --git a/src/Cake.Tests/project.json b/src/Cake.Tests/project.json index a00a9321ed..973b911e55 100644 --- a/src/Cake.Tests/project.json +++ b/src/Cake.Tests/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "dependencies": { "dotnet-test-xunit": "2.2.0-preview2-build1029", "Cake": { diff --git a/src/Cake.sln.DotSettings b/src/Cake.sln.DotSettings index d9e8cb13f3..53704c2a39 100644 --- a/src/Cake.sln.DotSettings +++ b/src/Cake.sln.DotSettings @@ -28,7 +28,10 @@ MSIL NET NSIS + TF + TFS VS + VSTS <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> True True diff --git a/src/Cake/CakeOptions.cs b/src/Cake/CakeOptions.cs index d2e19a751e..47b790f654 100644 --- a/src/Cake/CakeOptions.cs +++ b/src/Cake/CakeOptions.cs @@ -91,10 +91,10 @@ public sealed class CakeOptions public bool Experimental { get; set; } /// - /// Gets or sets a value indicating whether an error occured during parsing. + /// Gets or sets a value indicating whether an error occurred during parsing. /// /// - /// true if an error occured during parsing; otherwise, false. + /// true if an error occurred during parsing; otherwise, false. /// public bool HasError { get; set; } diff --git a/src/Cake/Scripting/Mono/MonoScriptSession.cs b/src/Cake/Scripting/Mono/MonoScriptSession.cs index a8f5c9d809..f507361865 100644 --- a/src/Cake/Scripting/Mono/MonoScriptSession.cs +++ b/src/Cake/Scripting/Mono/MonoScriptSession.cs @@ -115,7 +115,7 @@ public void Execute(Script script) catch (InternalErrorException) { // The error will be logged via the report printer. - throw new CakeException("An error occured while executing build script."); + throw new CakeException("An error occurred while executing build script."); } } } diff --git a/src/Cake/project.json b/src/Cake/project.json index 6f81158d6e..3f94b8cd10 100644 --- a/src/Cake/project.json +++ b/src/Cake/project.json @@ -1,5 +1,5 @@ { - "version": "0.16.2-*", + "version": "0.17.0-*", "buildOptions": { "emitEntryPoint": true, "xmlDoc": true, diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 990e73d871..2c56d6f618 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -10,7 +10,7 @@ using System.Reflection; [assembly: AssemblyProduct("Cake")] -[assembly: AssemblyVersion("0.16.2.0")] -[assembly: AssemblyFileVersion("0.16.2.0")] -[assembly: AssemblyInformationalVersion("0.16.2-beta.1+2.Branch.hotfix/0.16.2.Sha.a062c471b0a278c147756d435fae358b12fd22f3")] +[assembly: AssemblyVersion("0.17.0.0")] +[assembly: AssemblyFileVersion("0.17.0.0")] +[assembly: AssemblyInformationalVersion("0.17.0-beta.1+0.Branch.release/0.17.0.Sha.edc3cfda2d70f30acd59ba2092162ebe83482588")] [assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] \ No newline at end of file diff --git a/tests/integration/Cake.Common/IO/ZipAliases.cake b/tests/integration/Cake.Common/IO/ZipAliases.cake index fbcbb667d0..f988065585 100644 --- a/tests/integration/Cake.Common/IO/ZipAliases.cake +++ b/tests/integration/Cake.Common/IO/ZipAliases.cake @@ -7,7 +7,6 @@ Task("Cake.Common.IO.ZipAliases.Unzip") // Given var sourcePath = Paths.Resources.Combine("./Cake.Common/IO"); var sourceFile = sourcePath.CombineWithFilePath("./testfile.zip"); - var expectFile = sourcePath.CombineWithFilePath("./testfile.txt"); var targetPath = Paths.Temp.Combine("./Cake.Common.IO.ZipAliases/Unzip"); var targetFile = targetPath.CombineWithFilePath("testfile.txt"); @@ -25,7 +24,6 @@ Task("Cake.Common.IO.ZipAliases.Zip.FilePaths") { // Given var sourcePath = Paths.Resources.Combine("./Cake.Common/IO"); - var sourceFile = sourcePath.CombineWithFilePath("./testfile.txt"); var targetPath = Paths.Temp.Combine("./Cake.Common.IO.ZipAliases/FilePaths"); var targetFile = targetPath.CombineWithFilePath("testfile.zip"); @@ -44,7 +42,6 @@ Task("Cake.Common.IO.ZipAliases.Zip.Strings") { // Given var sourcePath = Paths.Resources.Combine("./Cake.Common/IO"); - var sourceFile = sourcePath.CombineWithFilePath("./testfile.txt"); var targetPath = Paths.Temp.Combine("./Cake.Common.IO.ZipAliases/Strings"); var targetFile = targetPath.CombineWithFilePath("testfile.zip");