diff --git a/.rwx/cake.yml b/.rwx/cake.yml new file mode 100644 index 0000000000..8ad19d5b0f --- /dev/null +++ b/.rwx/cake.yml @@ -0,0 +1,75 @@ +on: + github: + pull_request: + init: + commit-sha: ${{ event.git.sha }} + push: + - if: ${{ event.git.branch == 'develop' || event.git.branch == 'main' || starts-with(event.git.branch, 'hotfix/') }} + init: + commit-sha: ${{ event.git.sha }} + cli: + init: + commit-sha: ${{ event.git.sha }} + +base: + image: ubuntu:26.04 + config: rwx/base 1.1.1 + +tasks: + - key: code + call: git/clone 2.0.7 + with: + repository: https://github.com/cake-build/cake.git + ref: ${{ init.commit-sha }} + fetch-full-depth: true + preserve-git-dir: true + + - key: libicu-dev + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends libicu-dev + + - key: build + use: [code, libicu-dev] + run: | + # We clone at a commit SHA, so HEAD is detached; GitVersion needs a named branch ref. + # Use plumbing commands so the working tree (including any patched files) is untouched. + git branch -f develop HEAD + git symbolic-ref HEAD refs/heads/develop + + ./build.sh --target=Rwx --integration-tests-target=Cake.Common.Build.RwxProvider + env: + CAKE_INSTALL_SUPPORTED_SDKS: "true" + NuGetAudit: "false" + + - key: validate-output-artifact + use: [code, build] + run: | + CONTENTS=$(cat "$ARTIFACT_PATH") + if [ "$CONTENTS" != "cake integration test" ]; then + echo "Integration tests artifact contents are incorrect: '$CONTENTS'" + exit 1 + fi + echo "Integration tests artifact contents are correct: $CONTENTS" + env: + ARTIFACT_PATH: ${{ tasks.build.artifacts['cake-rwx-artifact.txt'] }} + + - key: validate-output-value + use: [code, build] + run: | + if [ "$OUTPUT_VALUE" != "ok" ]; then + echo "Output value contents are incorrect: '$CONTENTS'" + exit 1 + fi + echo "Output value contents are correct: $CONTENTS" + env: + OUTPUT_VALUE: ${{ tasks.build.values.cake_integration_test }} + + - key: validate-environment-variable + use: [code, build] + run: | + if [ "$CAKE_INTEGRATION_TEST" != "ok" ]; then + echo "Environment variable contents are incorrect: '$CAKE_INTEGRATION_TEST'" + exit 1 + fi + echo "Environment variable contents are correct: $CAKE_INTEGRATION_TEST" diff --git a/README.md b/README.md index b3e86279de..5023d26f27 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Cake (C# Make) is a build automation system with a C# DSL to do things like comp | GitLab | Debian | [![pipeline status](https://gitlab.com/cake-build/cake/badges/develop/pipeline.svg)](https://gitlab.com/cake-build/cake/commits/develop) | | | GitHub | Windows / Ubuntu/ macOS | [![Build Status](https://github.com/cake-build/cake/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/cake-build/cake/actions/workflows/build.yml) | | | Woodpecker CI | Debian | [![Woodpecker CI status](https://ci.codeberg.org/api/badges/15091/status.svg)](https://ci.codeberg.org/repos/15091) | [![Woodpecker CI Status](https://ci.codeberg.org/api/badges/15091/status.svg)](https://ci.codeberg.org/repos/15091) | +| RWX | Ubuntu | [![RWX Build Status](https://cloud.rwx.com/status_badges/cake.svg?branch=develop&definition=.rwx%2Fcake.yml&repo=cake)](https://cloud.rwx.com/runs/latest/cake?branch=develop&definition=.rwx%2Fcake.yml&repo=cake) | [![RWX Build Status](https://cloud.rwx.com/status_badges/cake.svg?branch=develop&definition=.rwx%2Fcake.yml&repo=cake)](https://cloud.rwx.com/runs/latest/cake?branch=develop&definition=.rwx%2Fcake.yml&repo=cake) | ## Code Coverage diff --git a/build.cake b/build.cake index 2d49a4185e..557c60f121 100644 --- a/build.cake +++ b/build.cake @@ -492,6 +492,9 @@ Task("GitHubActions-Release") Task("Travis") .IsDependentOn("Run-Unit-Tests"); +Task("Rwx") + .IsDependentOn("Run-Integration-Tests"); + Task("ReleaseNotes") .IsDependentOn("Create-Release-Notes"); diff --git a/src/Cake.Common.Tests/Fixtures/Build/RwxCommandsFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/RwxCommandsFixture.cs new file mode 100644 index 0000000000..118a8c0019 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/RwxCommandsFixture.cs @@ -0,0 +1,54 @@ +// 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.Rwx.Commands; +using Cake.Core; +using Cake.Core.IO; +using Cake.Testing; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class RwxCommandsFixture + { + public RwxInfoFixture InfoFixture { get; } + + public ICakeEnvironment Environment => InfoFixture.Environment; + + public FakeFileSystem FileSystem { get; } + + public RwxCommandsFixture() + { + InfoFixture = new RwxInfoFixture(); + Environment.WorkingDirectory.Returns("/work"); + FileSystem = new FakeFileSystem(Environment); + FileSystem.CreateDirectory("/rwx/values"); + FileSystem.CreateDirectory("/rwx/artifacts"); + FileSystem.CreateDirectory("/rwx/env"); + } + + public RwxCommands CreateRwxCommands() + { + return new RwxCommands(Environment, FileSystem, InfoFixture.CreateEnvironmentInfo()); + } + + public RwxCommandsFixture WithNoRwxValues() + { + Environment.GetEnvironmentVariable("RWX_VALUES").Returns(null as string); + return this; + } + + public RwxCommandsFixture WithNoRwxArtifacts() + { + Environment.GetEnvironmentVariable("RWX_ARTIFACTS").Returns(null as string); + return this; + } + + public RwxCommandsFixture WithNoRwxEnv() + { + Environment.GetEnvironmentVariable("RWX_ENV").Returns(null as string); + return this; + } + } +} diff --git a/src/Cake.Common.Tests/Fixtures/Build/RwxFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/RwxFixture.cs new file mode 100644 index 0000000000..f93d9ee28b --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/RwxFixture.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 Cake.Common.Build.Rwx; +using Cake.Core; +using Cake.Core.IO; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class RwxFixture + { + public ICakeEnvironment Environment { get; set; } + + public IFileSystem FileSystem { get; set; } + + public RwxFixture() + { + Environment = Substitute.For(); + FileSystem = Substitute.For(); + } + + public void IsRunningOnRwx() + { + Environment.GetEnvironmentVariable("RWX").Returns("true"); + } + + public RwxProvider CreateRwxProvider() + { + return new RwxProvider(Environment, FileSystem); + } + } +} diff --git a/src/Cake.Common.Tests/Fixtures/Build/RwxInfoFixture.cs b/src/Cake.Common.Tests/Fixtures/Build/RwxInfoFixture.cs new file mode 100644 index 0000000000..d998f7385e --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Build/RwxInfoFixture.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.Common.Build.Rwx.Data; +using Cake.Core; +using NSubstitute; + +namespace Cake.Common.Tests.Fixtures.Build +{ + internal sealed class RwxInfoFixture + { + public ICakeEnvironment Environment { get; set; } + + public RwxInfoFixture() + { + Environment = Substitute.For(); + + // RwxEnvironmentInfo + Environment.GetEnvironmentVariable("CI").Returns("true"); + Environment.GetEnvironmentVariable("RWX").Returns("true"); + + // RwxRunInfo + Environment.GetEnvironmentVariable("RWX_RUN_ID").Returns("01J9ABCDEFG"); + Environment.GetEnvironmentVariable("RWX_RUN_TITLE").Returns("Build and test"); + Environment.GetEnvironmentVariable("RWX_RUN_URL").Returns("https://cloud.rwx.com/runs/01J9ABCDEFG"); + + // RwxTaskInfo + Environment.GetEnvironmentVariable("RWX_TASK_ID").Returns("01J9TASKABC"); + Environment.GetEnvironmentVariable("RWX_TASK_URL").Returns("https://cloud.rwx.com/tasks/01J9TASKABC"); + Environment.GetEnvironmentVariable("RWX_TASK_ATTEMPT_NUMBER").Returns("2"); + + // RwxActorInfo + Environment.GetEnvironmentVariable("RWX_ACTOR_ID").Returns("usr_12345"); + Environment.GetEnvironmentVariable("RWX_ACTOR").Returns("octocat"); + + // RwxGitInfo + Environment.GetEnvironmentVariable("RWX_GIT_REPOSITORY_URL").Returns("https://github.com/cake-build/cake.git"); + Environment.GetEnvironmentVariable("RWX_GIT_REPOSITORY_NAME").Returns("cake-build/cake"); + Environment.GetEnvironmentVariable("RWX_GIT_COMMIT_SHA").Returns("0123456789abcdef0123456789abcdef01234567"); + Environment.GetEnvironmentVariable("RWX_GIT_COMMIT_MESSAGE").Returns("Add RWX build provider\n\nMore details here."); + Environment.GetEnvironmentVariable("RWX_GIT_COMMIT_SUMMARY").Returns("Add RWX build provider"); + Environment.GetEnvironmentVariable("RWX_GIT_COMMITTER_NAME").Returns("Octo Cat"); + Environment.GetEnvironmentVariable("RWX_GIT_COMMITTER_EMAIL").Returns("octocat@example.com"); + Environment.GetEnvironmentVariable("RWX_GIT_REF").Returns("refs/heads/main"); + Environment.GetEnvironmentVariable("RWX_GIT_REF_NAME").Returns("main"); + + // RwxRuntimeInfo + Environment.GetEnvironmentVariable("RWX_VALUES").Returns("/rwx/values"); + Environment.GetEnvironmentVariable("RWX_ARTIFACTS").Returns("/rwx/artifacts"); + Environment.GetEnvironmentVariable("RWX_ENV").Returns("/rwx/env"); + } + + public RwxRunInfo CreateRunInfo() + { + return new RwxRunInfo(Environment); + } + + public RwxTaskInfo CreateTaskInfo() + { + return new RwxTaskInfo(Environment); + } + + public RwxActorInfo CreateActorInfo() + { + return new RwxActorInfo(Environment); + } + + public RwxGitInfo CreateGitInfo() + { + return new RwxGitInfo(Environment); + } + + public RwxRuntimeInfo CreateRuntimeInfo() + { + return new RwxRuntimeInfo(Environment); + } + + public RwxEnvironmentInfo CreateEnvironmentInfo() + { + return new RwxEnvironmentInfo(Environment); + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs b/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs index 8729fea255..497d8cd155 100644 --- a/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs +++ b/src/Cake.Common.Tests/Unit/Build/BuildSystemTests.cs @@ -14,6 +14,7 @@ using Cake.Common.Build.GoCD; using Cake.Common.Build.Jenkins; using Cake.Common.Build.MyGet; +using Cake.Common.Build.Rwx; using Cake.Common.Build.TeamCity; using Cake.Common.Build.TravisCI; using Cake.Common.Build.WoodpeckerCI; @@ -44,9 +45,10 @@ public void Should_Throw_If_AppVeyor_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(null, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(null, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "appVeyorProvider"); @@ -69,9 +71,10 @@ public void Should_Throw_If_TeamCity_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, null, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, null, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "teamCityProvider"); @@ -94,9 +97,10 @@ public void Should_Throw_If_MyGet_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, null, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, null, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "myGetProvider"); @@ -119,9 +123,10 @@ public void Should_Throw_If_Bamboo_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, null, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, null, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "bambooProvider"); @@ -144,9 +149,10 @@ public void Should_Throw_If_ContinuaCI_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, null, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, null, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "continuaCIProvider"); @@ -169,9 +175,10 @@ public void Should_Throw_If_Jenkins_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, null, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, null, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "jenkinsProvider"); @@ -194,9 +201,10 @@ public void Should_Throw_If_Bitrise_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, null, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, null, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "bitriseProvider"); @@ -219,9 +227,10 @@ public void Should_Throw_If_TravisCI_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, null, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, null, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "travisCIProvider"); @@ -244,9 +253,10 @@ public void Should_Throw_If_BitbucketPipelines_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, null, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, null, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "bitbucketPipelinesProvider"); @@ -269,9 +279,10 @@ public void Should_Throw_If_GoCD_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, null, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, null, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "goCDProvider"); @@ -294,9 +305,10 @@ public void Should_Throw_If_GitLabCI_Is_Null() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, null, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, null, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "gitLabCIProvider"); @@ -319,9 +331,10 @@ public void Should_Throw_If_AzurePipelines_Is_Null() var gitLabCIProvider = Substitute.For(); var gitHubActionsProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, null, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, null, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "azurePipelinesProvider"); @@ -344,9 +357,10 @@ public void Should_Throw_If_GitHubActions_Is_Null() var gitLabCIProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, null, azurePipelinesProvider, woodpeckerCIProvider)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, null, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "gitHubActionsProvider"); @@ -369,13 +383,40 @@ public void Should_Throw_If_WoodpeckerCI_Is_Null() var gitLabCIProvider = Substitute.For(); var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); + var rwxProvider = Substitute.For(); // When - var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, null)); + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, null, rwxProvider)); // Then AssertEx.IsArgumentNullException(result, "woodpeckerCIProvider"); } + + [Fact] + public void Should_Throw_If_Rwx_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(); + var gitHubActionsProvider = Substitute.For(); + var azurePipelinesProvider = Substitute.For(); + var woodpeckerCIProvider = Substitute.For(); + + // When + var result = Record.Exception(() => new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, null)); + + // Then + AssertEx.IsArgumentNullException(result, "rwxProvider"); + } } public sealed class TheIsRunningOnAppVeyorProperty @@ -399,12 +440,13 @@ public void Should_Return_True_If_Running_On_AppVeyor() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); appVeyorProvider.IsRunningOnAppVeyor.Returns(true); appVeyorProvider.Environment.Returns(appVeyorEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnAppVeyor); @@ -432,12 +474,13 @@ public void Should_Return_True_If_Running_On_TeamCity() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); teamCityProvider.IsRunningOnTeamCity.Returns(true); teamCityProvider.Environment.Returns(teamCityEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnTeamCity); @@ -464,11 +507,12 @@ public void Should_Return_True_If_Running_On_MyGet() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); myGetProvider.IsRunningOnMyGet.Returns(true); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnMyGet); @@ -495,11 +539,12 @@ public void Should_Return_True_If_Running_On_Bamboo() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); bambooProvider.IsRunningOnBamboo.Returns(true); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnBamboo); @@ -526,11 +571,12 @@ public void Should_Return_True_If_Running_On_ContinuaCI() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); continuaCIProvider.IsRunningOnContinuaCI.Returns(true); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnContinuaCI); @@ -558,12 +604,13 @@ public void Should_Return_True_If_Running_On_Jenkins() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); jenkinsProvider.IsRunningOnJenkins.Returns(true); jenkinsProvider.Environment.Returns(jenkinsEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnJenkins); @@ -591,12 +638,13 @@ public void Should_Return_True_If_Running_On_Bitrise() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); bitriseProvider.IsRunningOnBitrise.Returns(true); bitriseProvider.Environment.Returns(bitriseEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnBitrise); @@ -624,12 +672,13 @@ public void Should_Return_True_If_Running_On_TravisCI() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); travisCIProvider.IsRunningOnTravisCI.Returns(true); travisCIProvider.Environment.Returns(travisCIEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnTravisCI); @@ -657,12 +706,13 @@ public void Should_Return_True_If_Running_On_BitbucketPipelines() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); bitbucketPipelinesProvider.IsRunningOnBitbucketPipelines.Returns(true); bitbucketPipelinesProvider.Environment.Returns(bitbucketPipelinesEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnBitbucketPipelines); @@ -689,11 +739,12 @@ public void Should_Return_True_If_Running_On_GoCD() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); goCDProvider.IsRunningOnGoCD.Returns(true); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnGoCD); @@ -721,12 +772,13 @@ public void Should_Return_True_If_Running_On_GitLabCI() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); gitLabCIProvider.IsRunningOnGitLabCI.Returns(true); gitLabCIProvider.Environment.Returns(gitLabCIEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnGitLabCI); @@ -754,12 +806,13 @@ public void Should_Return_True_If_Running_On_AzurePipelines() var azurePipelinesProvider = Substitute.For(); var azurePipelinesEnvironment = new AzurePipelinesInfoFixture().CreateEnvironmentInfo(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); azurePipelinesProvider.IsRunningOnAzurePipelines.Returns(true); azurePipelinesProvider.Environment.Returns(azurePipelinesEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnAzurePipelines); @@ -787,12 +840,13 @@ public void Should_Return_True_If_Running_On_GitHubActions() var gitHubActionsProvider = Substitute.For(); var gitHubActionsEnvironment = new GitHubActionsInfoFixture().CreateEnvironmentInfo(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); gitHubActionsProvider.IsRunningOnGitHubActions.Returns(true); gitHubActionsProvider.Environment.Returns(gitHubActionsEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnGitHubActions); @@ -802,22 +856,23 @@ public void Should_Return_True_If_Running_On_GitHubActions() public sealed class TheProviderProperty { [Theory] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.Local)] - [InlineData(true, false, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.AppVeyor)] - [InlineData(false, true, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.TeamCity)] - [InlineData(false, false, true, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.MyGet)] - [InlineData(false, false, false, true, false, false, false, false, false, false, false, false, false, false, BuildProvider.Bamboo)] - [InlineData(false, false, false, false, true, false, false, false, false, false, false, false, false, false, BuildProvider.ContinuaCI)] - [InlineData(false, false, false, false, false, true, false, false, false, false, false, false, false, false, BuildProvider.Jenkins)] - [InlineData(false, false, false, false, false, false, true, false, false, false, false, false, false, false, BuildProvider.Bitrise)] - [InlineData(false, false, false, false, false, false, false, true, false, false, false, false, false, false, BuildProvider.TravisCI)] - [InlineData(false, false, false, false, false, false, false, false, true, false, false, false, false, false, BuildProvider.BitbucketPipelines)] - [InlineData(false, false, false, false, false, false, false, false, false, true, false, false, false, false, BuildProvider.GoCD)] - [InlineData(false, false, false, false, false, false, false, false, false, false, true, false, false, false, BuildProvider.GitLabCI)] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, true, false, false, BuildProvider.AzurePipelines)] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, true, false, BuildProvider.GitHubActions)] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, true, BuildProvider.WoodpeckerCI)] - public void Should_Return_Provider_If_Running_On_Provider(bool appVeyor, bool teamCity, bool myGet, bool bamboo, bool continuaCI, bool jenkins, bool bitrise, bool travisCI, bool bitbucketPipelines, bool goCD, bool gitLabCI, bool azurePipelines, bool gitHubActions, bool woodpeckerCI, BuildProvider provider) + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.Local)] + [InlineData(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.AppVeyor)] + [InlineData(false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.TeamCity)] + [InlineData(false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.MyGet)] + [InlineData(false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, BuildProvider.Bamboo)] + [InlineData(false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, BuildProvider.ContinuaCI)] + [InlineData(false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, BuildProvider.Jenkins)] + [InlineData(false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, BuildProvider.Bitrise)] + [InlineData(false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, BuildProvider.TravisCI)] + [InlineData(false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, BuildProvider.BitbucketPipelines)] + [InlineData(false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, BuildProvider.GoCD)] + [InlineData(false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, BuildProvider.GitLabCI)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, BuildProvider.AzurePipelines)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, BuildProvider.GitHubActions)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, BuildProvider.WoodpeckerCI)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, BuildProvider.Rwx)] + public void Should_Return_Provider_If_Running_On_Provider(bool appVeyor, bool teamCity, bool myGet, bool bamboo, bool continuaCI, bool jenkins, bool bitrise, bool travisCI, bool bitbucketPipelines, bool goCD, bool gitLabCI, bool azurePipelines, bool gitHubActions, bool woodpeckerCI, bool rwx, BuildProvider provider) { // Given var appVeyorProvider = Substitute.For(); @@ -866,12 +921,16 @@ public void Should_Return_Provider_If_Running_On_Provider(bool appVeyor, bool te azurePipelinesProvider.IsRunningOnAzurePipelines.Returns(azurePipelines); azurePipelinesProvider.Environment.Returns(azurePipelinesEnvironment); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); var woodpeckerCIEnvironment = new WoodpeckerCIInfoFixture().CreateEnvironmentInfo(); woodpeckerCIProvider.IsRunningOnWoodpeckerCI.Returns(woodpeckerCI); woodpeckerCIProvider.Environment.Returns(woodpeckerCIEnvironment); + var rwxEnvironment = new RwxInfoFixture().CreateEnvironmentInfo(); + rwxProvider.IsRunningOnRwx.Returns(rwx); + rwxProvider.Environment.Returns(rwxEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.Equal(provider, buildSystem.Provider); @@ -881,22 +940,23 @@ public void Should_Return_Provider_If_Running_On_Provider(bool appVeyor, bool te public sealed class TheIsLocalBuildProperty { [Theory] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, true)] - [InlineData(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false)] - [InlineData(false, true, false, false, false, false, false, false, false, false, false, false, false, false, false)] - [InlineData(false, false, true, false, false, false, false, false, false, false, false, false, false, false, false)] - [InlineData(false, false, false, true, false, false, false, false, false, false, false, false, false, false, false)] - [InlineData(false, false, false, false, true, false, false, false, false, false, false, false, false, false, false)] - [InlineData(false, false, false, false, false, true, false, false, false, false, false, false, false, false, false)] - [InlineData(false, false, false, false, false, false, true, false, false, false, false, false, false, false, false)] - [InlineData(false, false, false, false, false, false, false, true, false, false, false, false, false, false, false)] - [InlineData(false, false, false, false, false, false, false, false, true, false, false, false, false, false, false)] - [InlineData(false, false, false, false, false, false, false, false, false, true, false, false, false, false, false)] - [InlineData(false, false, false, false, false, false, false, false, false, false, true, false, false, false, false)] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, true, false, false, false)] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, true, false, false)] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, true, false)] - public void Should_Return_Whether_Or_Not_Running_On_Provider(bool appVeyor, bool teamCity, bool myGet, bool bamboo, bool continuaCI, bool jenkins, bool bitrise, bool travisCI, bool bitbucketPipelines, bool goCD, bool gitLabCI, bool azurePipelines, bool gitHubActions, bool woodpeckerCI, bool isLocalBuild) + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true)] + [InlineData(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)] + [InlineData(false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false)] + [InlineData(false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false)] + [InlineData(false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false)] + [InlineData(false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false)] + [InlineData(false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false)] + [InlineData(false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false)] + [InlineData(false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false)] + [InlineData(false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false)] + [InlineData(false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false)] + [InlineData(false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false)] + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false)] + public void Should_Return_Whether_Or_Not_Running_On_Provider(bool appVeyor, bool teamCity, bool myGet, bool bamboo, bool continuaCI, bool jenkins, bool bitrise, bool travisCI, bool bitbucketPipelines, bool goCD, bool gitLabCI, bool azurePipelines, bool gitHubActions, bool woodpeckerCI, bool rwx, bool isLocalBuild) { // Given var appVeyorProvider = Substitute.For(); @@ -945,13 +1005,17 @@ public void Should_Return_Whether_Or_Not_Running_On_Provider(bool appVeyor, bool azurePipelinesProvider.IsRunningOnAzurePipelines.Returns(azurePipelines); azurePipelinesProvider.Environment.Returns(azurePipelinesEnvironment); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); var woodpeckerCIEnvironment = new WoodpeckerCIInfoFixture().CreateEnvironmentInfo(); woodpeckerCIProvider.IsRunningOnWoodpeckerCI.Returns(woodpeckerCI); woodpeckerCIProvider.Environment.Returns(woodpeckerCIEnvironment); + var rwxEnvironment = new RwxInfoFixture().CreateEnvironmentInfo(); + rwxProvider.IsRunningOnRwx.Returns(rwx); + rwxProvider.Environment.Returns(rwxEnvironment); // When System.Console.WriteLine(jenkinsProvider); - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.Equal(isLocalBuild, buildSystem.IsLocalBuild); @@ -978,38 +1042,74 @@ public void Should_Return_True_If_Running_On_WoodpeckerCI() var gitHubActionsProvider = Substitute.For(); var azurePipelinesProvider = Substitute.For(); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); var woodpeckerCIEnvironment = new WoodpeckerCIInfoFixture().CreateEnvironmentInfo(); woodpeckerCIProvider.IsRunningOnWoodpeckerCI.Returns(true); woodpeckerCIProvider.Environment.Returns(woodpeckerCIEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.True(buildSystem.IsRunningOnWoodpeckerCI); } } + public sealed class TheIsRunningOnRwxProperty + { + [Fact] + public void Should_Return_True_If_Running_On_Rwx() + { + // 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 gitHubActionsProvider = Substitute.For(); + var azurePipelinesProvider = Substitute.For(); + var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); + var rwxEnvironment = new RwxInfoFixture().CreateEnvironmentInfo(); + + rwxProvider.IsRunningOnRwx.Returns(true); + rwxProvider.Environment.Returns(rwxEnvironment); + + // When + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); + + // Then + Assert.True(buildSystem.IsRunningOnRwx); + } + } + public sealed class TheIsPullRequestProperty { [Theory] - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)] // none - [InlineData(true, false, false, false, false, false, false, false, false, false, false, false, false, false, true)] // appveyor - [InlineData(false, true, false, false, false, false, false, false, false, false, false, false, false, false, true)] // teamcity - [InlineData(false, false, true, false, false, false, false, false, false, false, false, false, false, false, false)] // myget - [InlineData(false, false, false, true, false, false, false, false, false, false, false, false, false, false, false)] // bamboo - [InlineData(false, false, false, false, true, false, false, false, false, false, false, false, false, false, false)] // continua - [InlineData(false, false, false, false, false, true, false, false, false, false, false, false, false, false, true)] // jenkins - [InlineData(false, false, false, false, false, false, true, false, false, false, false, false, false, false, true)] // bitrise - [InlineData(false, false, false, false, false, false, false, true, false, false, false, false, false, false, true)] // travis - [InlineData(false, false, false, false, false, false, false, false, true, false, false, false, false, false, true)] // bitbucket - [InlineData(false, false, false, false, false, false, false, false, false, true, false, false, false, false, false)] // gocd - [InlineData(false, false, false, false, false, false, false, false, false, false, true, false, false, false, true)] // gitlab - [InlineData(false, false, false, false, false, false, false, false, false, false, false, true, false, false, true)] // az pipelines - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, true, false, true)] // gh actions - [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, true, true)] // woodpecker - public void Should_Return_True_If_Running_On_Supported_Provider(bool appVeyor, bool teamCity, bool myGet, bool bamboo, bool continuaCI, bool jenkins, bool bitrise, bool travisCI, bool bitbucketPipelines, bool goCD, bool gitLabCI, bool azurePipelines, bool gitHubActions, bool woodpeckerCI, bool isPullRequest) + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false)] // none + [InlineData(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true)] // appveyor + [InlineData(false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true)] // teamcity + [InlineData(false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false)] // myget + [InlineData(false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false)] // bamboo + [InlineData(false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false)] // continua + [InlineData(false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true)] // jenkins + [InlineData(false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, true)] // bitrise + [InlineData(false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true)] // travis + [InlineData(false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, true)] // bitbucket + [InlineData(false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false)] // gocd + [InlineData(false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true)] // gitlab + [InlineData(false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true)] // az pipelines + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, true)] // gh actions + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true)] // woodpecker + [InlineData(false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false)] // rwx (no PR identifier exposed) + public void Should_Return_True_If_Running_On_Supported_Provider(bool appVeyor, bool teamCity, bool myGet, bool bamboo, bool continuaCI, bool jenkins, bool bitrise, bool travisCI, bool bitbucketPipelines, bool goCD, bool gitLabCI, bool azurePipelines, bool gitHubActions, bool woodpeckerCI, bool rwx, bool isPullRequest) { // Given var appVeyorProvider = Substitute.For(); @@ -1058,12 +1158,16 @@ public void Should_Return_True_If_Running_On_Supported_Provider(bool appVeyor, b azurePipelinesProvider.IsRunningOnAzurePipelines.Returns(azurePipelines); azurePipelinesProvider.Environment.Returns(azurePipelinesEnvironment); var woodpeckerCIProvider = Substitute.For(); + var rwxProvider = Substitute.For(); var woodpeckerCIEnvironment = new WoodpeckerCIInfoFixture().CreateEnvironmentInfo(); woodpeckerCIProvider.IsRunningOnWoodpeckerCI.Returns(woodpeckerCI); woodpeckerCIProvider.Environment.Returns(woodpeckerCIEnvironment); + var rwxEnvironment = new RwxInfoFixture().CreateEnvironmentInfo(); + rwxProvider.IsRunningOnRwx.Returns(rwx); + rwxProvider.Environment.Returns(rwxEnvironment); // When - var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + var buildSystem = new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); // Then Assert.Equal(isPullRequest, buildSystem.IsPullRequest); diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/Commands/RwxCommandsTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/Commands/RwxCommandsTests.cs new file mode 100644 index 0000000000..93de89dcfc --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/Commands/RwxCommandsTests.cs @@ -0,0 +1,396 @@ +// 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.IO; +using Cake.Common.Tests.Fixtures.Build; +using Cake.Core; +using Cake.Core.IO; +using Cake.Testing; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.Rwx.Commands +{ + public sealed class RwxCommandsTests + { + public sealed class TheSetValueMethod + { + [Fact] + public void Should_Write_Value_File() + { + // Given + var fixture = new RwxCommandsFixture(); + var commands = fixture.CreateRwxCommands(); + + // When + commands.SetValue("hello", "world"); + + // Then + var file = fixture.FileSystem.GetFile("/rwx/values/hello"); + Assert.True(file.Exists); + Assert.Equal("world", file.GetTextContent()); + } + + [Fact] + public void Should_Overwrite_Existing_Value() + { + // Given + var fixture = new RwxCommandsFixture(); + var commands = fixture.CreateRwxCommands(); + commands.SetValue("hello", "first"); + + // When + commands.SetValue("hello", "second"); + + // Then + Assert.Equal("second", fixture.FileSystem.GetFile("/rwx/values/hello").GetTextContent()); + } + + [Fact] + public void Should_Preserve_Multiline_Content_Verbatim() + { + // Given + var fixture = new RwxCommandsFixture(); + var commands = fixture.CreateRwxCommands(); + const string value = "line one\nline two\nline three"; + + // When + commands.SetValue("multi", value); + + // Then + Assert.Equal(value, fixture.FileSystem.GetFile("/rwx/values/multi").GetTextContent()); + } + + [Fact] + public void Should_Create_Values_Directory_When_Missing() + { + // Given + var fixture = new RwxCommandsFixture(); + fixture.FileSystem.GetDirectory("/rwx/values").Delete(true); + var commands = fixture.CreateRwxCommands(); + + // When + commands.SetValue("hello", "world"); + + // Then + Assert.True(fixture.FileSystem.GetFile("/rwx/values/hello").Exists); + } + + [Fact] + public void Should_Throw_On_Null_Key() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetValue(null, "value")); + + // Then + AssertEx.IsArgumentNullException(result, "key"); + } + + [Fact] + public void Should_Throw_On_Empty_Key() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetValue(string.Empty, "value")); + + // Then + AssertEx.IsArgumentNullException(result, "key"); + } + + [Fact] + public void Should_Throw_On_Null_Value() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetValue("key", null)); + + // Then + AssertEx.IsArgumentNullException(result, "value"); + } + + [Theory] + [InlineData("foo/bar")] + [InlineData("foo\\bar")] + [InlineData("..")] + [InlineData("../escape")] + public void Should_Throw_On_Key_With_Path_Components(string key) + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetValue(key, "value")); + + // Then + Assert.IsType(result); + } + + [Fact] + public void Should_Throw_When_Values_Path_Missing() + { + // Given + var fixture = new RwxCommandsFixture().WithNoRwxValues(); + var commands = fixture.CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetValue("key", "value")); + + // Then + Assert.IsType(result); + Assert.Contains("ValuesPath", result.Message); + } + } + + public sealed class TheSetEnvironmentVariableMethod + { + [Fact] + public void Should_Write_Env_File() + { + // Given + var fixture = new RwxCommandsFixture(); + var commands = fixture.CreateRwxCommands(); + + // When + commands.SetEnvironmentVariable("FOO", "bar"); + + // Then + var file = fixture.FileSystem.GetFile("/rwx/env/FOO"); + Assert.True(file.Exists); + Assert.Equal("bar", file.GetTextContent()); + } + + [Fact] + public void Should_Overwrite_Existing_Env_Var() + { + // Given + var fixture = new RwxCommandsFixture(); + var commands = fixture.CreateRwxCommands(); + commands.SetEnvironmentVariable("FOO", "first"); + + // When + commands.SetEnvironmentVariable("FOO", "second"); + + // Then + Assert.Equal("second", fixture.FileSystem.GetFile("/rwx/env/FOO").GetTextContent()); + } + + [Fact] + public void Should_Write_Value_Verbatim_Without_Trailing_Newline() + { + // Given + var fixture = new RwxCommandsFixture(); + var commands = fixture.CreateRwxCommands(); + + // When + commands.SetEnvironmentVariable("FOO", "bar"); + + // Then + // RWX trims a single trailing \n when materializing the env var; writing verbatim + // lets callers decide whether they want one, and `bar` stays `bar`. + Assert.Equal("bar", fixture.FileSystem.GetFile("/rwx/env/FOO").GetTextContent()); + } + + [Fact] + public void Should_Create_Env_Directory_When_Missing() + { + // Given + var fixture = new RwxCommandsFixture(); + fixture.FileSystem.GetDirectory("/rwx/env").Delete(true); + var commands = fixture.CreateRwxCommands(); + + // When + commands.SetEnvironmentVariable("FOO", "bar"); + + // Then + Assert.True(fixture.FileSystem.GetFile("/rwx/env/FOO").Exists); + } + + [Fact] + public void Should_Throw_On_Null_Name() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetEnvironmentVariable(null, "value")); + + // Then + AssertEx.IsArgumentNullException(result, "name"); + } + + [Fact] + public void Should_Throw_On_Empty_Name() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetEnvironmentVariable(string.Empty, "value")); + + // Then + AssertEx.IsArgumentNullException(result, "name"); + } + + [Fact] + public void Should_Throw_On_Null_Value() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetEnvironmentVariable("FOO", null)); + + // Then + AssertEx.IsArgumentNullException(result, "value"); + } + + [Theory] + [InlineData("foo/bar")] + [InlineData("foo\\bar")] + [InlineData("..")] + [InlineData("../escape")] + public void Should_Throw_On_Name_With_Path_Components(string name) + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetEnvironmentVariable(name, "value")); + + // Then + Assert.IsType(result); + } + + [Fact] + public void Should_Throw_When_Env_Path_Missing() + { + // Given + var fixture = new RwxCommandsFixture().WithNoRwxEnv(); + var commands = fixture.CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.SetEnvironmentVariable("FOO", "bar")); + + // Then + Assert.IsType(result); + Assert.Contains("EnvPath", result.Message); + } + } + + public sealed class TheUploadArtifactFileMethod + { + [Fact] + public void Should_Copy_File_To_Artifacts_Directory() + { + // Given + var fixture = new RwxCommandsFixture(); + fixture.FileSystem.CreateFile("/work/output/report.txt").SetContent("payload"); + var commands = fixture.CreateRwxCommands(); + + // When + commands.UploadArtifact("/work/output/report.txt"); + + // Then + var artifact = fixture.FileSystem.GetFile("/rwx/artifacts/report.txt"); + Assert.True(artifact.Exists); + Assert.Equal("payload", artifact.GetTextContent()); + } + + [Fact] + public void Should_Resolve_Relative_Paths_Against_Working_Directory() + { + // Given + var fixture = new RwxCommandsFixture(); + fixture.FileSystem.CreateFile("/work/report.txt").SetContent("payload"); + var commands = fixture.CreateRwxCommands(); + + // When + commands.UploadArtifact("report.txt"); + + // Then + Assert.True(fixture.FileSystem.GetFile("/rwx/artifacts/report.txt").Exists); + } + + [Fact] + public void Should_Overwrite_Existing_Artifact() + { + // Given + var fixture = new RwxCommandsFixture(); + fixture.FileSystem.CreateFile("/work/report.txt").SetContent("new"); + fixture.FileSystem.CreateFile("/rwx/artifacts/report.txt").SetContent("old"); + var commands = fixture.CreateRwxCommands(); + + // When + commands.UploadArtifact("/work/report.txt"); + + // Then + Assert.Equal("new", fixture.FileSystem.GetFile("/rwx/artifacts/report.txt").GetTextContent()); + } + + [Fact] + public void Should_Create_Artifacts_Directory_When_Missing() + { + // Given + var fixture = new RwxCommandsFixture(); + fixture.FileSystem.GetDirectory("/rwx/artifacts").Delete(true); + fixture.FileSystem.CreateFile("/work/report.txt").SetContent("payload"); + var commands = fixture.CreateRwxCommands(); + + // When + commands.UploadArtifact("/work/report.txt"); + + // Then + Assert.True(fixture.FileSystem.GetFile("/rwx/artifacts/report.txt").Exists); + } + + [Fact] + public void Should_Throw_On_Null_Path() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.UploadArtifact((FilePath)null)); + + // Then + AssertEx.IsArgumentNullException(result, "path"); + } + + [Fact] + public void Should_Throw_When_Source_File_Missing() + { + // Given + var commands = new RwxCommandsFixture().CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.UploadArtifact("/work/does-not-exist.txt")); + + // Then + Assert.IsType(result); + } + + [Fact] + public void Should_Throw_When_Artifacts_Path_Missing() + { + // Given + var fixture = new RwxCommandsFixture().WithNoRwxArtifacts(); + fixture.FileSystem.CreateFile("/work/report.txt").SetContent("payload"); + var commands = fixture.CreateRwxCommands(); + + // When + var result = Record.Exception(() => commands.UploadArtifact("/work/report.txt")); + + // Then + Assert.IsType(result); + Assert.Contains("ArtifactsPath", result.Message); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxActorInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxActorInfoTests.cs new file mode 100644 index 0000000000..cd4f0cac4e --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxActorInfoTests.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.Rwx.Data +{ + public sealed class RwxActorInfoTests + { + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateActorInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal("usr_12345", result); + } + } + + public sealed class TheNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateActorInfo(); + + // When + var result = info.Name; + + // Then + Assert.Equal("octocat", result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxGitInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxGitInfoTests.cs new file mode 100644 index 0000000000..3eb93a0386 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxGitInfoTests.cs @@ -0,0 +1,156 @@ +// 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.Rwx.Data +{ + public sealed class RwxGitInfoTests + { + public sealed class TheRepositoryUrlProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.RepositoryUrl; + + // Then + Assert.Equal("https://github.com/cake-build/cake.git", result); + } + } + + public sealed class TheRepositoryNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.RepositoryName; + + // Then + Assert.Equal("cake-build/cake", result); + } + } + + public sealed class TheCommitShaProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.CommitSha; + + // Then + Assert.Equal("0123456789abcdef0123456789abcdef01234567", result); + } + } + + public sealed class TheCommitMessageProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.CommitMessage; + + // Then + Assert.Equal("Add RWX build provider\n\nMore details here.", result); + } + } + + public sealed class TheCommitSummaryProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.CommitSummary; + + // Then + Assert.Equal("Add RWX build provider", result); + } + } + + public sealed class TheCommitterNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.CommitterName; + + // Then + Assert.Equal("Octo Cat", result); + } + } + + public sealed class TheCommitterEmailProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.CommitterEmail; + + // Then + Assert.Equal("octocat@example.com", result); + } + } + + public sealed class TheRefProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.Ref; + + // Then + Assert.Equal("refs/heads/main", result); + } + } + + public sealed class TheRefNameProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateGitInfo(); + + // When + var result = info.RefName; + + // Then + Assert.Equal("main", result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxRunInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxRunInfoTests.cs new file mode 100644 index 0000000000..1f4bb64ca9 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxRunInfoTests.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.Rwx.Data +{ + public sealed class RwxRunInfoTests + { + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateRunInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal("01J9ABCDEFG", result); + } + } + + public sealed class TheTitleProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateRunInfo(); + + // When + var result = info.Title; + + // Then + Assert.Equal("Build and test", result); + } + } + + public sealed class TheUrlProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateRunInfo(); + + // When + var result = info.Url; + + // Then + Assert.Equal("https://cloud.rwx.com/runs/01J9ABCDEFG", result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxRuntimeInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxRuntimeInfoTests.cs new file mode 100644 index 0000000000..0d2ae019bb --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxRuntimeInfoTests.cs @@ -0,0 +1,167 @@ +// 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 NSubstitute; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.Rwx.Data +{ + public sealed class RwxRuntimeInfoTests + { + public sealed class TheValuesPathProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateRuntimeInfo(); + + // When + var result = info.ValuesPath; + + // Then + Assert.Equal("/rwx/values", result.FullPath); + } + + [Fact] + public void Should_Return_Null_When_Env_Var_Missing() + { + // Given + var fixture = new RwxInfoFixture(); + fixture.Environment.GetEnvironmentVariable("RWX_VALUES").Returns(null as string); + var info = fixture.CreateRuntimeInfo(); + + // When + var result = info.ValuesPath; + + // Then + Assert.Null(result); + } + } + + public sealed class TheArtifactsPathProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateRuntimeInfo(); + + // When + var result = info.ArtifactsPath; + + // Then + Assert.Equal("/rwx/artifacts", result.FullPath); + } + + [Fact] + public void Should_Return_Null_When_Env_Var_Missing() + { + // Given + var fixture = new RwxInfoFixture(); + fixture.Environment.GetEnvironmentVariable("RWX_ARTIFACTS").Returns(null as string); + var info = fixture.CreateRuntimeInfo(); + + // When + var result = info.ArtifactsPath; + + // Then + Assert.Null(result); + } + } + + public sealed class TheEnvPathProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateRuntimeInfo(); + + // When + var result = info.EnvPath; + + // Then + Assert.Equal("/rwx/env", result.FullPath); + } + + [Fact] + public void Should_Return_Null_When_Env_Var_Missing() + { + // Given + var fixture = new RwxInfoFixture(); + fixture.Environment.GetEnvironmentVariable("RWX_ENV").Returns(null as string); + var info = fixture.CreateRuntimeInfo(); + + // When + var result = info.EnvPath; + + // Then + Assert.Null(result); + } + } + + public sealed class TheIsRuntimeAvailableProperty + { + [Fact] + public void Should_Return_True_When_All_Env_Vars_Set() + { + // Given + var info = new RwxInfoFixture().CreateRuntimeInfo(); + + // When + var result = info.IsRuntimeAvailable; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_When_Values_Missing() + { + // Given + var fixture = new RwxInfoFixture(); + fixture.Environment.GetEnvironmentVariable("RWX_VALUES").Returns(null as string); + var info = fixture.CreateRuntimeInfo(); + + // When + var result = info.IsRuntimeAvailable; + + // Then + Assert.False(result); + } + + [Fact] + public void Should_Return_False_When_Artifacts_Missing() + { + // Given + var fixture = new RwxInfoFixture(); + fixture.Environment.GetEnvironmentVariable("RWX_ARTIFACTS").Returns(null as string); + var info = fixture.CreateRuntimeInfo(); + + // When + var result = info.IsRuntimeAvailable; + + // Then + Assert.False(result); + } + + [Fact] + public void Should_Return_False_When_Env_Missing() + { + // Given + var fixture = new RwxInfoFixture(); + fixture.Environment.GetEnvironmentVariable("RWX_ENV").Returns(null as string); + var info = fixture.CreateRuntimeInfo(); + + // When + var result = info.IsRuntimeAvailable; + + // Then + Assert.False(result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxTaskInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxTaskInfoTests.cs new file mode 100644 index 0000000000..933e946959 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/Data/RwxTaskInfoTests.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.Rwx.Data +{ + public sealed class RwxTaskInfoTests + { + public sealed class TheIdProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateTaskInfo(); + + // When + var result = info.Id; + + // Then + Assert.Equal("01J9TASKABC", result); + } + } + + public sealed class TheUrlProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateTaskInfo(); + + // When + var result = info.Url; + + // Then + Assert.Equal("https://cloud.rwx.com/tasks/01J9TASKABC", result); + } + } + + public sealed class TheAttemptNumberProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateTaskInfo(); + + // When + var result = info.AttemptNumber; + + // Then + Assert.Equal(2, result); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/RwxEnvironmentInfoTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/RwxEnvironmentInfoTests.cs new file mode 100644 index 0000000000..68a0569976 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/RwxEnvironmentInfoTests.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.Common.Tests.Fixtures.Build; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.Rwx +{ + public sealed class RwxEnvironmentInfoTests + { + public sealed class TheCIProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateEnvironmentInfo(); + + // When + var result = info.CI; + + // Then + Assert.True(result); + } + } + + public sealed class TheRwxProperty + { + [Fact] + public void Should_Return_Correct_Value() + { + // Given + var info = new RwxInfoFixture().CreateEnvironmentInfo(); + + // When + var result = info.Rwx; + + // Then + Assert.True(result); + } + } + + public sealed class TheRuntimeProperty + { + [Fact] + public void Should_Be_Populated() + { + // Given + var info = new RwxInfoFixture().CreateEnvironmentInfo(); + + // When, Then + Assert.NotNull(info.Runtime); + Assert.Equal("/rwx/values", info.Runtime.ValuesPath.FullPath); + Assert.Equal("/rwx/artifacts", info.Runtime.ArtifactsPath.FullPath); + } + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Build/Rwx/RwxProviderTests.cs b/src/Cake.Common.Tests/Unit/Build/Rwx/RwxProviderTests.cs new file mode 100644 index 0000000000..81b7d7726b --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Build/Rwx/RwxProviderTests.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.Common.Build.Rwx; +using Cake.Common.Tests.Fixtures.Build; +using Cake.Core.IO; +using Cake.Testing; +using NSubstitute; +using Xunit; + +namespace Cake.Common.Tests.Unit.Build.Rwx +{ + public sealed class RwxProviderTests + { + [Fact] + public void Should_Throw_If_Environment_Is_Null() + { + // Given, When + var result = Record.Exception(() => new RwxProvider(null, Substitute.For())); + + // Then + AssertEx.IsArgumentNullException(result, "environment"); + } + + [Fact] + public void Should_Throw_If_FileSystem_Is_Null() + { + // Given, When + var result = Record.Exception(() => new RwxProvider(Substitute.For(), null)); + + // Then + AssertEx.IsArgumentNullException(result, "fileSystem"); + } + + public sealed class TheIsRunningOnRwxProperty + { + [Fact] + public void Should_Return_True_When_RWX_Env_Var_Set() + { + // Given + var fixture = new RwxFixture(); + fixture.IsRunningOnRwx(); + var provider = fixture.CreateRwxProvider(); + + // When + var result = provider.IsRunningOnRwx; + + // Then + Assert.True(result); + } + + [Fact] + public void Should_Return_False_When_RWX_Env_Var_Not_Set() + { + // Given + var fixture = new RwxFixture(); + var provider = fixture.CreateRwxProvider(); + + // When + var result = provider.IsRunningOnRwx; + + // Then + Assert.False(result); + } + } + } +} diff --git a/src/Cake.Common/Build/BuildProvider.cs b/src/Cake.Common/Build/BuildProvider.cs index 6db517b7c0..1b8a69bedc 100644 --- a/src/Cake.Common/Build/BuildProvider.cs +++ b/src/Cake.Common/Build/BuildProvider.cs @@ -85,6 +85,11 @@ public enum BuildProvider /// /// WoodpeckerCI build provider. /// - WoodpeckerCI = 16384 + WoodpeckerCI = 16384, + + /// + /// RWX build provider. + /// + Rwx = 32768 } } \ No newline at end of file diff --git a/src/Cake.Common/Build/BuildSystem.cs b/src/Cake.Common/Build/BuildSystem.cs index 15dc348e76..b8b17d3f93 100644 --- a/src/Cake.Common/Build/BuildSystem.cs +++ b/src/Cake.Common/Build/BuildSystem.cs @@ -14,6 +14,7 @@ using Cake.Common.Build.GoCD; using Cake.Common.Build.Jenkins; using Cake.Common.Build.MyGet; +using Cake.Common.Build.Rwx; using Cake.Common.Build.TeamCity; using Cake.Common.Build.TravisCI; using Cake.Common.Build.WoodpeckerCI; @@ -43,6 +44,7 @@ public sealed class BuildSystem /// The GitHub Actions provider. /// The Azure Pipelines provider. /// The WoodpeckerCI provider. + /// The RWX provider. public BuildSystem( IAppVeyorProvider appVeyorProvider, ITeamCityProvider teamCityProvider, @@ -57,7 +59,8 @@ public BuildSystem( IGitLabCIProvider gitLabCIProvider, IGitHubActionsProvider gitHubActionsProvider, IAzurePipelinesProvider azurePipelinesProvider, - IWoodpeckerCIProvider woodpeckerCIProvider) + IWoodpeckerCIProvider woodpeckerCIProvider, + IRwxProvider rwxProvider) { ArgumentNullException.ThrowIfNull(appVeyorProvider); ArgumentNullException.ThrowIfNull(teamCityProvider); @@ -73,6 +76,7 @@ public BuildSystem( ArgumentNullException.ThrowIfNull(gitHubActionsProvider); ArgumentNullException.ThrowIfNull(azurePipelinesProvider); ArgumentNullException.ThrowIfNull(woodpeckerCIProvider); + ArgumentNullException.ThrowIfNull(rwxProvider); AppVeyor = appVeyorProvider; TeamCity = teamCityProvider; @@ -88,6 +92,7 @@ public BuildSystem( GitHubActions = gitHubActionsProvider; AzurePipelines = azurePipelinesProvider; WoodpeckerCI = woodpeckerCIProvider; + Rwx = rwxProvider; Provider = (AppVeyor.IsRunningOnAppVeyor ? BuildProvider.AppVeyor : BuildProvider.Local) | (TeamCity.IsRunningOnTeamCity ? BuildProvider.TeamCity : BuildProvider.Local) @@ -102,7 +107,8 @@ public BuildSystem( | (GitLabCI.IsRunningOnGitLabCI ? BuildProvider.GitLabCI : BuildProvider.Local) | (GitHubActions.IsRunningOnGitHubActions ? BuildProvider.GitHubActions : BuildProvider.Local) | (AzurePipelines.IsRunningOnAzurePipelines ? BuildProvider.AzurePipelines : BuildProvider.Local) - | (WoodpeckerCI.IsRunningOnWoodpeckerCI ? BuildProvider.WoodpeckerCI : BuildProvider.Local); + | (WoodpeckerCI.IsRunningOnWoodpeckerCI ? BuildProvider.WoodpeckerCI : BuildProvider.Local) + | (Rwx.IsRunningOnRwx ? BuildProvider.Rwx : BuildProvider.Local); IsLocalBuild = Provider == BuildProvider.Local; @@ -558,6 +564,37 @@ public BuildSystem( /// public IWoodpeckerCIProvider WoodpeckerCI { get; } + /// + /// Gets a value indicating whether this instance is running on RWX. + /// + /// + /// + /// if (BuildSystem.IsRunningOnRwx) + /// { + /// // Get the run identifier. + /// var runId = BuildSystem.Rwx.Environment.Run.Id; + /// } + /// + /// + /// + /// true if this instance is running on RWX; otherwise, false. + /// + public bool IsRunningOnRwx => Rwx.IsRunningOnRwx; + + /// + /// Gets the RWX Provider. + /// + /// + /// + /// if (BuildSystem.IsRunningOnRwx) + /// { + /// // Get the run URL. + /// var runUrl = BuildSystem.Rwx.Environment.Run.Url; + /// } + /// + /// + public IRwxProvider Rwx { get; } + /// /// Gets the current build provider. /// diff --git a/src/Cake.Common/Build/BuildSystemAliases.cs b/src/Cake.Common/Build/BuildSystemAliases.cs index b8b237f933..1a0b0e33ef 100644 --- a/src/Cake.Common/Build/BuildSystemAliases.cs +++ b/src/Cake.Common/Build/BuildSystemAliases.cs @@ -14,6 +14,7 @@ using Cake.Common.Build.GoCD; using Cake.Common.Build.Jenkins; using Cake.Common.Build.MyGet; +using Cake.Common.Build.Rwx; using Cake.Common.Build.TeamCity; using Cake.Common.Build.TravisCI; using Cake.Common.Build.WoodpeckerCI; @@ -58,8 +59,9 @@ public static BuildSystem BuildSystem(this ICakeContext context) var gitHubActionsProvider = new GitHubActionsProvider(context.Environment, context.FileSystem, new BuildSystemServiceMessageWriter()); var azurePipelinesProvider = new AzurePipelinesProvider(context.Environment, new BuildSystemServiceMessageWriter()); var woodpeckerCIProvider = new WoodpeckerCIProvider(context.Environment, context.FileSystem); + var rwxProvider = new RwxProvider(context.Environment, context.FileSystem); - return new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider); + return new BuildSystem(appVeyorProvider, teamCityProvider, myGetProvider, bambooProvider, continuaCIProvider, jenkinsProvider, bitriseProvider, travisCIProvider, bitbucketPipelinesProvider, goCDProvider, gitLabCIProvider, gitHubActionsProvider, azurePipelinesProvider, woodpeckerCIProvider, rwxProvider); } /// @@ -367,5 +369,27 @@ public static IWoodpeckerCIProvider WoodpeckerCI(this ICakeContext context) var buildSystem = context.BuildSystem(); return buildSystem.WoodpeckerCI; } + + /// + /// Gets an instance that can be used to + /// obtain information from the RWX environment. + /// + /// + /// + /// var isRwxBuild = Rwx.IsRunningOnRwx; + /// + /// + /// The context. + /// A instance. + [CakePropertyAlias(Cache = true)] + [CakeNamespaceImport("Cake.Common.Build.Rwx")] + [CakeNamespaceImport("Cake.Common.Build.Rwx.Data")] + public static IRwxProvider Rwx(this ICakeContext context) + { + ArgumentNullException.ThrowIfNull(context); + + var buildSystem = context.BuildSystem(); + return buildSystem.Rwx; + } } } \ No newline at end of file diff --git a/src/Cake.Common/Build/Rwx/Commands/RwxCommands.cs b/src/Cake.Common/Build/Rwx/Commands/RwxCommands.cs new file mode 100644 index 0000000000..4096bce6c3 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Commands/RwxCommands.cs @@ -0,0 +1,165 @@ +// 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.IO; +using Cake.Common.Build.Rwx.Data; +using Cake.Core; +using Cake.Core.IO; + +namespace Cake.Common.Build.Rwx.Commands +{ + /// + /// Provides RWX commands for the current build, allowing tasks to write + /// output values, export environment variables to downstream tasks, and + /// upload artifacts at runtime via the filesystem conventions documented at + /// , + /// , + /// and . + /// + public sealed class RwxCommands + { + private readonly ICakeEnvironment _environment; + private readonly IFileSystem _fileSystem; + private readonly RwxEnvironmentInfo _rwxEnvironment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + /// The file system. + /// The RWX environment. + public RwxCommands( + ICakeEnvironment environment, + IFileSystem fileSystem, + RwxEnvironmentInfo rwxEnvironment) + { + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); + _rwxEnvironment = rwxEnvironment ?? throw new ArgumentNullException(nameof(rwxEnvironment)); + } + + /// + /// Sets an RWX output value for the current task. The value is written to + /// {RWX_VALUES}/{key}; each key is a separate file, so repeated + /// calls with the same key overwrite the previous value. Multiline values + /// are written verbatim. + /// + /// The value key. May not contain path separators or ... + /// The value contents. + public void SetValue(string key, string value) + { + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentNullException(nameof(key)); + } + + ArgumentNullException.ThrowIfNull(value); + + // RWX writes each value into its own file inside $RWX_VALUES, keyed by filename. + // A separator or `..` in the key would let callers write outside that directory. + if (key.Contains('/') || key.Contains('\\') || key.Contains("..")) + { + throw new CakeException("RWX value key may not contain path separators or '..'."); + } + + if (_rwxEnvironment.Runtime.ValuesPath == null) + { + throw new CakeException("RWX Runtime ValuesPath missing."); + } + + var valuesPath = _rwxEnvironment.Runtime.ValuesPath.MakeAbsolute(_environment); + var valuesDirectory = _fileSystem.GetDirectory(valuesPath); + if (!valuesDirectory.Exists) + { + valuesDirectory.Create(); + } + + var targetPath = valuesPath.CombineWithFilePath(key); + var file = _fileSystem.GetFile(targetPath); + using var stream = file.Open(FileMode.Create, FileAccess.Write, FileShare.None); + using var writer = new StreamWriter(stream); + writer.Write(value); + } + + /// + /// Exports an environment variable for downstream RWX tasks. The value is + /// written to {RWX_ENV}/{name}; each name is a separate file, so + /// repeated calls with the same name overwrite the previous value. The + /// variable becomes visible to tasks that depend on the current one via + /// use. Note that RWX trims a single trailing \n from the + /// file contents when materializing the variable. + /// + /// The environment variable name. May not contain path separators or ... + /// The environment variable value. + public void SetEnvironmentVariable(string name, string value) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + + ArgumentNullException.ThrowIfNull(value); + + // RWX writes each env var into its own file inside $RWX_ENV, keyed by filename; + // files in subdirectories are ignored by the runtime. A separator or `..` in the + // name would let callers write outside that directory or into an ignored location. + if (name.Contains('/') || name.Contains('\\') || name.Contains("..")) + { + throw new CakeException("RWX environment variable name may not contain path separators or '..'."); + } + + if (_rwxEnvironment.Runtime.EnvPath == null) + { + throw new CakeException("RWX Runtime EnvPath missing."); + } + + var envPath = _rwxEnvironment.Runtime.EnvPath.MakeAbsolute(_environment); + var envDirectory = _fileSystem.GetDirectory(envPath); + if (!envDirectory.Exists) + { + envDirectory.Create(); + } + + var targetPath = envPath.CombineWithFilePath(name); + var file = _fileSystem.GetFile(targetPath); + using var stream = file.Open(FileMode.Create, FileAccess.Write, FileShare.None); + using var writer = new StreamWriter(stream); + writer.Write(value); + } + + /// + /// Uploads a file as an RWX artifact for the current task. The file is + /// copied into {RWX_ARTIFACTS}/{filename}, where filename is + /// the leaf name of . + /// + /// Path to the local file to upload. + public void UploadArtifact(FilePath path) + { + ArgumentNullException.ThrowIfNull(path); + + if (_rwxEnvironment.Runtime.ArtifactsPath == null) + { + throw new CakeException("RWX Runtime ArtifactsPath missing."); + } + + var absoluteFilePath = path.MakeAbsolute(_environment); + var file = _fileSystem.GetFile(absoluteFilePath); + if (!file.Exists) + { + throw new FileNotFoundException("Artifact file not found.", absoluteFilePath.FullPath); + } + + var artifactsPath = _rwxEnvironment.Runtime.ArtifactsPath.MakeAbsolute(_environment); + var artifactsDirectory = _fileSystem.GetDirectory(artifactsPath); + if (!artifactsDirectory.Exists) + { + artifactsDirectory.Create(); + } + + var destination = artifactsPath.CombineWithFilePath(absoluteFilePath.GetFilename()); + file.Copy(destination, true); + } + } +} diff --git a/src/Cake.Common/Build/Rwx/Data/RwxActorInfo.cs b/src/Cake.Common/Build/Rwx/Data/RwxActorInfo.cs new file mode 100644 index 0000000000..19df1e2d7b --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Data/RwxActorInfo.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.Rwx.Data +{ + /// + /// Provides RWX actor information for the current build. + /// + public sealed class RwxActorInfo : RwxInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public RwxActorInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the identifier of the RWX actor that started the run. + /// + /// + /// The actor identifier. + /// + public string Id => GetEnvironmentString("RWX_ACTOR_ID"); + + /// + /// Gets the name of the RWX actor that started the run. + /// + /// + /// The actor name. + /// + public string Name => GetEnvironmentString("RWX_ACTOR"); + } +} diff --git a/src/Cake.Common/Build/Rwx/Data/RwxEnvironmentInfo.cs b/src/Cake.Common/Build/Rwx/Data/RwxEnvironmentInfo.cs new file mode 100644 index 0000000000..499622044e --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Data/RwxEnvironmentInfo.cs @@ -0,0 +1,290 @@ +// 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.Rwx.Data +{ + /// + /// Provides RWX environment information for the current build. + /// + public sealed class RwxEnvironmentInfo : RwxInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public RwxEnvironmentInfo(ICakeEnvironment environment) + : base(environment) + { + Run = new RwxRunInfo(environment); + Task = new RwxTaskInfo(environment); + Actor = new RwxActorInfo(environment); + Git = new RwxGitInfo(environment); + Runtime = new RwxRuntimeInfo(environment); + } + + /// + /// Gets RWX run information for the current build. + /// + /// + /// The run. + /// + /// Via BuildSystem. + /// + /// + /// if (BuildSystem.Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Run: + /// Id: {0} + /// Title: {1} + /// Url: {2}", + /// BuildSystem.Rwx.Environment.Run.Id, + /// BuildSystem.Rwx.Environment.Run.Title, + /// BuildSystem.Rwx.Environment.Run.Url + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + /// Via Rwx. + /// + /// + /// if (Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Run: + /// Id: {0} + /// Title: {1} + /// Url: {2}", + /// Rwx.Environment.Run.Id, + /// Rwx.Environment.Run.Title, + /// Rwx.Environment.Run.Url + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + public RwxRunInfo Run { get; } + + /// + /// Gets RWX task information for the current build. + /// + /// + /// The task. + /// + /// Via BuildSystem. + /// + /// + /// if (BuildSystem.Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Task: + /// Id: {0} + /// Url: {1} + /// AttemptNumber: {2}", + /// BuildSystem.Rwx.Environment.Task.Id, + /// BuildSystem.Rwx.Environment.Task.Url, + /// BuildSystem.Rwx.Environment.Task.AttemptNumber + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + /// Via Rwx. + /// + /// + /// if (Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Task: + /// Id: {0} + /// Url: {1} + /// AttemptNumber: {2}", + /// Rwx.Environment.Task.Id, + /// Rwx.Environment.Task.Url, + /// Rwx.Environment.Task.AttemptNumber + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + public RwxTaskInfo Task { get; } + + /// + /// Gets RWX actor information for the current build. + /// + /// + /// The actor. + /// + /// Via BuildSystem. + /// + /// + /// if (BuildSystem.Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Actor: + /// Id: {0} + /// Name: {1}", + /// BuildSystem.Rwx.Environment.Actor.Id, + /// BuildSystem.Rwx.Environment.Actor.Name + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + /// Via Rwx. + /// + /// + /// if (Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Actor: + /// Id: {0} + /// Name: {1}", + /// Rwx.Environment.Actor.Id, + /// Rwx.Environment.Actor.Name + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + public RwxActorInfo Actor { get; } + + /// + /// Gets RWX git information for the current build. + /// + /// + /// The git information. Populated by the RWX git/clone package, so it is only + /// available to tasks that depend (directly or transitively) on a task that ran + /// git/clone; otherwise the properties return empty strings. + /// + /// Via BuildSystem. + /// + /// + /// if (BuildSystem.Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Git: + /// RepositoryUrl: {0} + /// CommitSha: {1} + /// RefName: {2}", + /// BuildSystem.Rwx.Environment.Git.RepositoryUrl, + /// BuildSystem.Rwx.Environment.Git.CommitSha, + /// BuildSystem.Rwx.Environment.Git.RefName + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + /// Via Rwx. + /// + /// + /// if (Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Git: + /// RepositoryUrl: {0} + /// CommitSha: {1} + /// RefName: {2}", + /// Rwx.Environment.Git.RepositoryUrl, + /// Rwx.Environment.Git.CommitSha, + /// Rwx.Environment.Git.RefName + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + public RwxGitInfo Git { get; } + + /// + /// Gets RWX runtime information for the current build. Exposes the + /// filesystem locations RWX uses for runtime-written output values and + /// artifacts. Available inside any task running on RWX. + /// + /// + /// The runtime information. + /// + /// Via BuildSystem. + /// + /// + /// if (BuildSystem.Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Runtime: + /// ValuesPath: {0} + /// ArtifactsPath: {1}", + /// BuildSystem.Rwx.Environment.Runtime.ValuesPath, + /// BuildSystem.Rwx.Environment.Runtime.ArtifactsPath + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + /// Via Rwx. + /// + /// + /// if (Rwx.IsRunningOnRwx) + /// { + /// Information( + /// @"Runtime: + /// ValuesPath: {0} + /// ArtifactsPath: {1}", + /// Rwx.Environment.Runtime.ValuesPath, + /// Rwx.Environment.Runtime.ArtifactsPath + /// ); + /// } + /// else + /// { + /// Information("Not running on RWX"); + /// } + /// + /// + public RwxRuntimeInfo Runtime { get; } + + /// + /// Gets a value indicating whether the current build is continuous integration. + /// + /// + /// true if ci; otherwise, false. + /// + public bool CI => GetEnvironmentBoolean("CI"); + + /// + /// Gets a value indicating whether the environment is RWX. + /// + /// + /// true if RWX; otherwise, false. + /// + public bool Rwx => GetEnvironmentBoolean("RWX"); + } +} diff --git a/src/Cake.Common/Build/Rwx/Data/RwxGitInfo.cs b/src/Cake.Common/Build/Rwx/Data/RwxGitInfo.cs new file mode 100644 index 0000000000..7819282a96 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Data/RwxGitInfo.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.Core; + +namespace Cake.Common.Build.Rwx.Data +{ + /// + /// Provides RWX git information for the current build. + /// + /// + /// These values are populated by the RWX git/clone package and are + /// only available to tasks that depend (directly or transitively) on a task + /// that ran git/clone. When unavailable, properties return empty strings. + /// + public sealed class RwxGitInfo : RwxInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public RwxGitInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the URL of the git repository that was cloned. + /// + /// + /// The repository parameter provided to git/clone. + /// + public string RepositoryUrl => GetEnvironmentString("RWX_GIT_REPOSITORY_URL"); + + /// + /// Gets the repository identifier extracted from the repository URL. + /// + /// + /// The repository identifier (for example, cake-build/cake). + /// + public string RepositoryName => GetEnvironmentString("RWX_GIT_REPOSITORY_NAME"); + + /// + /// Gets the SHA of the resolved commit. + /// + /// + /// The resolved commit SHA. + /// + public string CommitSha => GetEnvironmentString("RWX_GIT_COMMIT_SHA"); + + /// + /// Gets the full message of the resolved commit. + /// + /// + /// The resolved commit message. + /// + public string CommitMessage => GetEnvironmentString("RWX_GIT_COMMIT_MESSAGE"); + + /// + /// Gets the summary line of the resolved commit's message. + /// + /// + /// The first line of the resolved commit message. + /// + public string CommitSummary => GetEnvironmentString("RWX_GIT_COMMIT_SUMMARY"); + + /// + /// Gets the committer name associated with the resolved commit. + /// + /// + /// The committer name. + /// + public string CommitterName => GetEnvironmentString("RWX_GIT_COMMITTER_NAME"); + + /// + /// Gets the committer email associated with the resolved commit. + /// + /// + /// The committer email. + /// + public string CommitterEmail => GetEnvironmentString("RWX_GIT_COMMITTER_EMAIL"); + + /// + /// Gets the unresolved ref associated with the commit. + /// + /// + /// The unresolved ref (for example, refs/heads/main or refs/tags/v1.0.0). + /// + public string Ref => GetEnvironmentString("RWX_GIT_REF"); + + /// + /// Gets the name of the unresolved ref associated with the commit. + /// + /// + /// The short ref name (for example, the branch or tag name extracted from the full ref path). + /// + public string RefName => GetEnvironmentString("RWX_GIT_REF_NAME"); + } +} diff --git a/src/Cake.Common/Build/Rwx/Data/RwxRunInfo.cs b/src/Cake.Common/Build/Rwx/Data/RwxRunInfo.cs new file mode 100644 index 0000000000..3eb208883d --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Data/RwxRunInfo.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.Rwx.Data +{ + /// + /// Provides RWX run information for the current build. + /// + public sealed class RwxRunInfo : RwxInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public RwxRunInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the RWX identifier of the current run. + /// + /// + /// The run identifier. + /// + public string Id => GetEnvironmentString("RWX_RUN_ID"); + + /// + /// Gets the title of the current RWX run. + /// + /// + /// The run title. + /// + public string Title => GetEnvironmentString("RWX_RUN_TITLE"); + + /// + /// Gets the link to the current run in RWX. + /// + /// + /// The run URL. + /// + public string Url => GetEnvironmentString("RWX_RUN_URL"); + } +} diff --git a/src/Cake.Common/Build/Rwx/Data/RwxRuntimeInfo.cs b/src/Cake.Common/Build/Rwx/Data/RwxRuntimeInfo.cs new file mode 100644 index 0000000000..4a46e50857 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Data/RwxRuntimeInfo.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 Cake.Core; +using Cake.Core.IO; + +namespace Cake.Common.Build.Rwx.Data +{ + /// + /// Provides RWX runtime information for the current build, exposing the + /// directories RWX uses for output values and artifacts. These are written to + /// at task execution time and complement static outputs.values / + /// outputs.artifacts declarations in the task YAML. + /// + public sealed class RwxRuntimeInfo : RwxInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public RwxRuntimeInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the directory in which output values can be written. Each file + /// in this directory becomes an output value keyed by its filename. + /// + /// + /// The path resolved from the RWX_VALUES environment variable, or + /// null if the variable is not set. + /// + public DirectoryPath ValuesPath => GetEnvironmentDirectoryPath("RWX_VALUES"); + + /// + /// Gets the directory into which artifacts can be uploaded. Files copied + /// into this directory are captured as artifacts of the current task. + /// + /// + /// The path resolved from the RWX_ARTIFACTS environment variable, or + /// null if the variable is not set. + /// + public DirectoryPath ArtifactsPath => GetEnvironmentDirectoryPath("RWX_ARTIFACTS"); + + /// + /// Gets the directory into which environment variables can be exported + /// for downstream tasks. Each file in this directory becomes an + /// environment variable in tasks that depend on the current one via + /// use, keyed by filename. + /// + /// + /// The path resolved from the RWX_ENV environment variable, or + /// null if the variable is not set. + /// + public DirectoryPath EnvPath => GetEnvironmentDirectoryPath("RWX_ENV"); + + /// + /// Gets a value indicating whether the values, artifacts, and env + /// directories are all exposed by the current RWX runtime. + /// + /// + /// true if , , + /// and are all set; otherwise, false. + /// + public bool IsRuntimeAvailable => ValuesPath != null && ArtifactsPath != null && EnvPath != null; + } +} diff --git a/src/Cake.Common/Build/Rwx/Data/RwxTaskInfo.cs b/src/Cake.Common/Build/Rwx/Data/RwxTaskInfo.cs new file mode 100644 index 0000000000..78b14bfd27 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/Data/RwxTaskInfo.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.Rwx.Data +{ + /// + /// Provides RWX task information for the current build. + /// + public sealed class RwxTaskInfo : RwxInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The environment. + public RwxTaskInfo(ICakeEnvironment environment) + : base(environment) + { + } + + /// + /// Gets the RWX identifier of the current task. + /// + /// + /// The task identifier. + /// + public string Id => GetEnvironmentString("RWX_TASK_ID"); + + /// + /// Gets the link to the current task in RWX. + /// + /// + /// The task URL. + /// + public string Url => GetEnvironmentString("RWX_TASK_URL"); + + /// + /// Gets the attempt number of the current RWX task. + /// + /// + /// The task attempt number. + /// + public int AttemptNumber => GetEnvironmentInteger("RWX_TASK_ATTEMPT_NUMBER"); + } +} diff --git a/src/Cake.Common/Build/Rwx/IRwxProvider.cs b/src/Cake.Common/Build/Rwx/IRwxProvider.cs new file mode 100644 index 0000000000..a8891596e7 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/IRwxProvider.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.Build.Rwx.Commands; +using Cake.Common.Build.Rwx.Data; + +namespace Cake.Common.Build.Rwx +{ + /// + /// Represents an RWX Provider. + /// + public interface IRwxProvider + { + /// + /// Gets a value indicating whether this instance is running on RWX. + /// + /// + /// true if this instance is running on RWX; otherwise, false. + /// + bool IsRunningOnRwx { get; } + + /// + /// Gets the environment. + /// + /// + /// The environment. + /// + RwxEnvironmentInfo Environment { get; } + + /// + /// Gets the RWX commands surface, used to write output values and upload + /// artifacts at task runtime. + /// + /// + /// The commands. + /// + RwxCommands Commands { get; } + } +} diff --git a/src/Cake.Common/Build/Rwx/RwxInfo.cs b/src/Cake.Common/Build/Rwx/RwxInfo.cs new file mode 100644 index 0000000000..b6c7215792 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/RwxInfo.cs @@ -0,0 +1,83 @@ +// 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; + +namespace Cake.Common.Build.Rwx +{ + /// + /// Base class used to provide information about the RWX environment. + /// + public abstract class RwxInfo + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + protected RwxInfo(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, or null if it is not set. + protected DirectoryPath GetEnvironmentDirectoryPath(string variable) + { + return _environment.GetEnvironmentVariable(variable) is string value + ? DirectoryPath.FromString(value) + : null; + } + + /// + /// 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; + } + } +} diff --git a/src/Cake.Common/Build/Rwx/RwxProvider.cs b/src/Cake.Common/Build/Rwx/RwxProvider.cs new file mode 100644 index 0000000000..3b40244798 --- /dev/null +++ b/src/Cake.Common/Build/Rwx/RwxProvider.cs @@ -0,0 +1,42 @@ +// 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.Rwx.Commands; +using Cake.Common.Build.Rwx.Data; +using Cake.Core; +using Cake.Core.IO; + +namespace Cake.Common.Build.Rwx +{ + /// + /// Responsible for communicating with RWX. + /// + public sealed class RwxProvider : IRwxProvider + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment. + /// The file system. + public RwxProvider(ICakeEnvironment environment, IFileSystem fileSystem) + { + _environment = environment ?? throw new ArgumentNullException(nameof(environment)); + ArgumentNullException.ThrowIfNull(fileSystem); + Environment = new RwxEnvironmentInfo(environment); + Commands = new RwxCommands(environment, fileSystem, Environment); + } + + /// + public bool IsRunningOnRwx => !string.IsNullOrWhiteSpace(_environment.GetEnvironmentVariable("RWX")); + + /// + public RwxEnvironmentInfo Environment { get; } + + /// + public RwxCommands Commands { get; } + } +} diff --git a/tests/integration/Cake.Common/Build/BuildSystemAliases.cake b/tests/integration/Cake.Common/Build/BuildSystemAliases.cake index 1afccff5a2..b3716d31a8 100644 --- a/tests/integration/Cake.Common/Build/BuildSystemAliases.cake +++ b/tests/integration/Cake.Common/Build/BuildSystemAliases.cake @@ -1,6 +1,7 @@ #load "GitHubActions/GitHubActionsProvider.cake" #load "AzurePipelines/AzurePipelinesProvider.cake" #load "WoodpeckerCI/WoodpeckerCIProvider.cake" +#load "Rwx/RwxProvider.cake" Task("Cake.Common.Build.BuildSystemAliases.BuildProvider") .DoesForEach( @@ -14,4 +15,5 @@ Task("Cake.Common.Build.BuildSystemAliases") .IsDependentOn("Cake.Common.Build.BuildSystemAliases.BuildProvider") .IsDependentOn("Cake.Common.Build.GitHubActionsProvider") .IsDependentOn("Cake.Common.Build.AzurePipelinesProvider") - .IsDependentOn("Cake.Common.Build.WoodpeckerCIProvider"); \ No newline at end of file + .IsDependentOn("Cake.Common.Build.WoodpeckerCIProvider") + .IsDependentOn("Cake.Common.Build.RwxProvider"); \ No newline at end of file diff --git a/tests/integration/Cake.Common/Build/Rwx/RwxProvider.cake b/tests/integration/Cake.Common/Build/Rwx/RwxProvider.cake new file mode 100644 index 0000000000..95cdfff780 --- /dev/null +++ b/tests/integration/Cake.Common/Build/Rwx/RwxProvider.cake @@ -0,0 +1,67 @@ +#load "./../../../utilities/xunit.cake" + +Task("Cake.Common.Build.RwxProvider.Provider") + .Does(() => { + Assert.Equal(BuildProvider.Rwx, BuildSystem.Provider); +}); + +Task("Cake.Common.Build.RwxProvider.Environment") + .Does(() => { + Information("RWX Provider:"); + Information(" IsRunningOnRwx: {0}", BuildSystem.Rwx.IsRunningOnRwx); + + Information(" Environment:"); + Information(" CI: {0}", BuildSystem.Rwx.Environment.CI); + Information(" Rwx: {0}", BuildSystem.Rwx.Environment.Rwx); + + Information(" Run:"); + Information(" Id: {0}", BuildSystem.Rwx.Environment.Run.Id); + Information(" Title: {0}", BuildSystem.Rwx.Environment.Run.Title); + Information(" Url: {0}", BuildSystem.Rwx.Environment.Run.Url); + + Information(" Task:"); + Information(" Id: {0}", BuildSystem.Rwx.Environment.Task.Id); + Information(" Url: {0}", BuildSystem.Rwx.Environment.Task.Url); + Information(" AttemptNumber: {0}", BuildSystem.Rwx.Environment.Task.AttemptNumber); + + Information(" Actor:"); + Information(" Id: {0}", BuildSystem.Rwx.Environment.Actor.Id); + Information(" Name: {0}", BuildSystem.Rwx.Environment.Actor.Name); + + Information(" Git:"); + Information(" RepositoryUrl: {0}", BuildSystem.Rwx.Environment.Git.RepositoryUrl); + Information(" RepositoryName: {0}", BuildSystem.Rwx.Environment.Git.RepositoryName); + Information(" CommitSha: {0}", BuildSystem.Rwx.Environment.Git.CommitSha); + Information(" CommitSummary: {0}", BuildSystem.Rwx.Environment.Git.CommitSummary); + Information(" CommitterName: {0}", BuildSystem.Rwx.Environment.Git.CommitterName); + Information(" CommitterEmail: {0}", BuildSystem.Rwx.Environment.Git.CommitterEmail); + Information(" Ref: {0}", BuildSystem.Rwx.Environment.Git.Ref); + Information(" RefName: {0}", BuildSystem.Rwx.Environment.Git.RefName); + + Information(" Runtime:"); + Information(" ValuesPath: {0}", BuildSystem.Rwx.Environment.Runtime.ValuesPath); + Information(" ArtifactsPath: {0}", BuildSystem.Rwx.Environment.Runtime.ArtifactsPath); + Information(" EnvPath: {0}", BuildSystem.Rwx.Environment.Runtime.EnvPath); + Information(" IsRuntimeAvailable: {0}", BuildSystem.Rwx.Environment.Runtime.IsRuntimeAvailable); +}); + +Task("Cake.Common.Build.RwxProvider.Commands") + .Does(() => { + BuildSystem.Rwx.Commands.SetValue("cake_integration_test", "ok"); + BuildSystem.Rwx.Commands.SetEnvironmentVariable("CAKE_INTEGRATION_TEST", "ok"); + + var artifactSource = Paths.Temp.CombineWithFilePath("cake-rwx-artifact.txt"); + EnsureDirectoryExist(artifactSource.GetDirectory()); + System.IO.File.WriteAllText(artifactSource.FullPath, "cake integration test"); + BuildSystem.Rwx.Commands.UploadArtifact(artifactSource); +}); + +var rwxProviderTask = Task("Cake.Common.Build.RwxProvider") + .IsDependentOn("Cake.Common.Build.RwxProvider.Environment"); + +if (BuildSystem.Rwx.IsRunningOnRwx) +{ + rwxProviderTask + .IsDependentOn("Cake.Common.Build.RwxProvider.Provider") + .IsDependentOn("Cake.Common.Build.RwxProvider.Commands"); +}