From 8c83e3a78fb5543987bb3772980851cbadb92cab Mon Sep 17 00:00:00 2001 From: "Fischer, Louis" Date: Wed, 22 Mar 2023 22:55:37 -0500 Subject: [PATCH] Added Cake Frosting switch --- .gitignore | 6 +++++ README.md | 30 +++++++++++++++++---- __tests__/cake.test.ts | 59 ++++++++++++++++++++++++++++++++++++++++++ __tests__/main.test.ts | 22 ++++++++++++++++ action.yml | 5 +++- dist/index.js | 36 ++++++++++++++++++++++---- src/action.ts | 2 ++ src/cake.ts | 23 ++++++++++++++++ src/main.ts | 14 +++++++--- 9 files changed, 182 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index a44a138..2b2207c 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,9 @@ typings/ # Secret files .secrets + +# bin folder +bin/ + +# obj folder +obj/ \ No newline at end of file diff --git a/README.md b/README.md index 79ddbf4..252c500 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GitHub Marketplace](https://img.shields.io/github/v/release/cake-build/cake-action?label=Marketplace&sort=semver)](https://github.com/marketplace/actions/cake-action) [![GitHub Actions Build](https://github.com/cake-build/cake-action/workflows/Build/badge.svg)](https://github.com/cake-build/cake-action/actions?workflow=Build) [![GitHub Actions Tests](https://github.com/cake-build/cake-action/workflows/Tests/badge.svg)](https://github.com/cake-build/cake-action/actions?workflow=Tests) [![Coveralls](https://coveralls.io/repos/github/cake-build/cake-action/badge.svg?branch=master)](https://coveralls.io/github/cake-build/cake-action?branch=master) -This action allows you to run a Cake script from your GitHub Actions workflow without having to use a [bootstrapper](https://github.com/cake-build/resources). +This action allows you to run a Cake script or Cake Frosting project from your GitHub Actions workflow without having to use a [bootstrapper](https://github.com/cake-build/resources). ## Usage @@ -14,7 +14,9 @@ steps: uses: cake-build/cake-action@v2 ``` -The Cake action will look for a script named `build.cake` in your repository's root directory and run it for you using the [Cake Tool](https://www.nuget.org/packages/Cake.Tool/). All output from the Cake script will be automatically redirected to the build log for inspection. +The Cake action will look for a script named `build.cake` in your repository's root directory and run it for you using the [Cake Tool](https://www.nuget.org/packages/Cake.Tool/). If you are using a [Cake Frosting](https://cakebuild.net/docs/running-builds/runners/cake-frosting) project, the `csproj-path` parameter must be specified and the `script-path` is ignored. + +All output from the Cake script or Cake Frosting project will be automatically redirected to the build log for inspection. ## Inputs @@ -30,9 +32,21 @@ steps: script-path: path/to/script.cake ``` +### `csproj-path` + +If you are using [Cake Frosting](https://cakebuild.net/docs/running-builds/runners/cake-frosting), you can specify the path with the `csproj-path` [input parameter](https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepswith): + +```yml +steps: + - name: Run Cake Frosting + uses: cake-build/cake-action@v2 + with: + csproj-path: ./path/to/build.csproj +``` + ### `target` -You'll likely want to specify which task to run out of the ones defined in the Cake script. For that, you can use the `target` parameter: +You'll likely want to specify which task to run out of the ones defined in the Cake script or Cake Frosting project. For that, you can use the `target` parameter: ```yml steps: @@ -88,7 +102,11 @@ The arguments are defined in a [multi-line string literal](https://yaml.org/spec ### `cake-version` -By default, the Cake action will run your script using the latest _stable_ version of the [Cake .NET Core Global tool](https://www.nuget.org/packages/Cake.Tool/). However, if for some reason you want to [use a specific version of Cake](https://cakebuild.net/docs/tutorials/pinning-cake-version) (for compatibility with older third-party addins, for example), you can do so by specifying the version number in the `cake-version` parameter: +By default, the Cake action will run your script using the latest _stable_ version of the [Cake .NET Core Global tool](https://www.nuget.org/packages/Cake.Tool/). + +_Ignored_ for Cake Frosting Project. + +If for some reason you want to [use a specific version of Cake](https://cakebuild.net/docs/tutorials/pinning-cake-version) (for compatibility with older third-party addins, for example), you can do so by specifying the version number in the `cake-version` parameter.: ```yml steps: @@ -112,6 +130,8 @@ steps: As of [Cake 1.0.0](https://github.com/cake-build/cake/releases/tag/v1.0.0), any [custom modules](https://cakebuild.net/docs/fundamentals/modules) that you reference in your script are [bootstrapped automatically](https://github.com/cake-build/cake/issues/2833) upon running it. +_Ignored_ for Cake Frosting Project. + If you're using an older version of Cake, however, you need to explicitly [bootstrap](https://cakebuild.net/docs/fundamentals/preprocessor-directives#module-directive) them before running the script. The Cake action can take care of this extra step for you by setting the `cake-bootstrap` parameter to `explicit`: ```yml @@ -137,7 +157,7 @@ The default value is `auto`, which means that the modules will be automatically ## Cross-platform -Since the [Cake Tool](https://www.nuget.org/packages/Cake.Tool/) is built on .NET Core, the Cake action will run on any of the [virtual environments](https://help.github.com/en/github/automating-your-workflow-with-github-actions/software-in-virtual-environments-for-github-actions) supported by GitHub Actions, namely Linux, Windows and macOS. +Since the [Cake Tool](https://www.nuget.org/packages/Cake.Tool/) and [Cake Frosting](https://www.nuget.org/packages/Cake.Frosting) are built on .NET Core, the Cake action will run on any of the [virtual environments](https://help.github.com/en/github/automating-your-workflow-with-github-actions/software-in-virtual-environments-for-github-actions) supported by GitHub Actions, namely Linux, Windows and macOS. This allows you to define your build step exactly _once_ and run it on multiple operating systems _in parallel_ by defining a [build matrix](https://help.github.com/en/github/automating-your-workflow-with-github-actions/configuring-a-workflow#configuring-a-build-matrix): diff --git a/__tests__/cake.test.ts b/__tests__/cake.test.ts index 02b1170..a768c16 100644 --- a/__tests__/cake.test.ts +++ b/__tests__/cake.test.ts @@ -8,7 +8,9 @@ import { CakeArgument, CakeSwitch } from '../src/cakeParameter'; const pathToLocalToolsDirectory = path.join('path', 'to', 'tool'); const pathToLocalTool = path.join(pathToLocalToolsDirectory, 'dotnet-cake'); +const pathToCsprojFile = path.join('build', 'Build.csproj'); const dotnetManifestCake = 'dotnet tool run dotnet-cake'; +const dotnetRun = 'dotnet run'; jest.mock('@actions/exec'); jest.mock('@actions/io'); @@ -190,3 +192,60 @@ describe('When running a script successfully using the tool manifest', () => { ['script.cake', '--switch']); }); }); + +describe('When running a Cake Frosting project successfully', () => { + const fakeExec = exec as jest.MockedFunction; + const fakeToolsDirectory = new ToolsDirectory(); + + beforeAll(async () => { + fakeExec.mockReturnValue(Promise.resolve(0)); + }); + + test('it should run with the default non-required parameters', async () => { + await cake.runProject(pathToCsprojFile, fakeToolsDirectory); + + expect(fakeExec).toHaveBeenCalledWith( + dotnetRun, + [ + '--project', pathToCsprojFile, + '--no-launch-profile', + '--verbosity', 'minimal', + '--configuration', 'Release', + '--', + `--paths_tools="${fakeToolsDirectory.path}"` + ]); + }); + + test('it should run with the specified parameters', async () => { + await cake.runProject( + pathToCsprojFile, + fakeToolsDirectory, + new CakeArgument('param', 'arg'), + new CakeSwitch('switch')); + + expect(fakeExec).toHaveBeenCalledWith( + dotnetRun, + [ + '--project', pathToCsprojFile, + '--no-launch-profile', + '--verbosity', 'minimal', + '--configuration', 'Release', + '--', + `--paths_tools="${fakeToolsDirectory.path}"`, + '--param=arg', + '--switch' + ]); + }); +}); + +describe('When failing to run a Cake Frosting Project', () => { + const fakeExec = exec as jest.MockedFunction; + + beforeAll(() => { + fakeExec.mockReturnValue(Promise.resolve(-21)); + }); + + test('it should throw an error containing the exit code', async () => { + await expect(cake.runProject('', new ToolsDirectory())).rejects.toThrow('-21'); + }); +}); diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index fb2f2be..de976cd 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -67,6 +67,28 @@ describe('When running the action with the script path input argument', () => { }); }); +describe('When running the action with the csproj path input argument', () => { + const fakeGetInputs = action.getInputs as jest.MockedFunction; + const fakeRunProject = cake.runProject as jest.MockedFunction; + + beforeAll(() => { + fakeGetInputs.mockReturnValue({ + csprojPath: './path/to/build.csproj', + scriptArguments: [] + }); + }); + + test('it should run the Cake Frosting Project', async () => { + await run(); + expect(cake.runProject).toHaveBeenCalled(); + }); + + test('it should run the specified Cake Frosting project', async () => { + await run(); + expect(fakeRunProject.mock.calls[0][0]).toBe('./path/to/build.csproj'); + }); +}); + describe('When running the action with tool-manifest as the Cake version input argument', () => { const fakeGetInputs = action.getInputs as jest.MockedFunction; const fakeInstallCakeTool = cakeTool.install as jest.MockedFunction; diff --git a/action.yml b/action.yml index ff9a130..ab30ddc 100644 --- a/action.yml +++ b/action.yml @@ -1,5 +1,5 @@ name: 'Cake Action' -description: 'Run a Cake script as part of your build.' +description: 'Run a Cake script or Cake Frosting project as part of your build.' author: 'Enrico Campidoglio' branding: icon: 'box' @@ -9,6 +9,9 @@ inputs: description: 'The path of the Cake script to run.' required: false default: 'build.cake' + csproj-path: + description: 'The path of the Cake Frosting Project to run. Takes precedence over script-path' + required: false target: description: 'The name of the task to execute. Note that this argument must be supported by the script.' required: false diff --git a/dist/index.js b/dist/index.js index 5762626..42d106a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3991,6 +3991,7 @@ const input = __importStar(__nccwpck_require__(6747)); function getInputs() { return { scriptPath: core.getInput('script-path'), + csprojPath: core.getInput('csproj-path'), cakeVersion: getCakeVersionInput(), cakeBootstrap: getCakeBootstrapInput(), scriptArguments: getScriptInputs() @@ -4070,11 +4071,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.bootstrapScript = exports.runScript = void 0; +exports.bootstrapScript = exports.runProject = exports.runScript = void 0; const exec_1 = __nccwpck_require__(1514); const io_1 = __nccwpck_require__(7436); const dotnetCake = 'dotnet-cake'; const dotnetLocalToolCake = 'dotnet tool run dotnet-cake'; +const dotnetRun = 'dotnet run'; function runScript(scriptPath = 'build.cake', cakeToolSettings, ...params) { return __awaiter(this, void 0, void 0, function* () { const cakeToolPath = yield resolveCakeToolPath(cakeToolSettings); @@ -4086,6 +4088,24 @@ function runScript(scriptPath = 'build.cake', cakeToolSettings, ...params) { }); } exports.runScript = runScript; +function runProject(csprojPath, toolsDir, ...params) { + return __awaiter(this, void 0, void 0, function* () { + const cakeParams = formatParameters(params); + const exitCode = yield (0, exec_1.exec)(dotnetRun, [ + '--project', csprojPath, + '--no-launch-profile', + '--verbosity', 'minimal', + '--configuration', 'Release', + '--', + `--paths_tools="${toolsDir}"`, + ...cakeParams + ]); + if (exitCode != 0) { + throw new Error(`Failed to run the csproj. Exit code: ${exitCode}`); + } + }); +} +exports.runProject = runProject; function bootstrapScript(scriptPath = 'build.cake', cakeToolSettings) { return __awaiter(this, void 0, void 0, function* () { const cakeToolPath = yield resolveCakeToolPath(cakeToolSettings); @@ -4515,6 +4535,7 @@ function run() { try { const inputs = action.getInputs(); const scriptPath = inputs.scriptPath; + const csprojPath = inputs.csprojPath; const version = inputs.cakeVersion; const bootstrap = inputs.cakeBootstrap; const toolsDir = new toolsDirectory_1.ToolsDirectory(); @@ -4522,11 +4543,16 @@ function run() { const cakeToolSettings = new cakeToolSettings_1.CakeToolSettings(toolsDir, (version === null || version === void 0 ? void 0 : version.version) === 'tool-manifest'); dotnet.disableTelemetry(); dotnet.disableWelcomeMessage(); - yield cakeTool.install(toolsDir, version); - if (bootstrap === 'explicit') { - yield cake.bootstrapScript(scriptPath, cakeToolSettings); + if (csprojPath) { + yield cake.runProject(csprojPath, toolsDir, ...inputs.scriptArguments); + } + else { + yield cakeTool.install(toolsDir, version); + if (bootstrap === 'explicit') { + yield cake.bootstrapScript(scriptPath, cakeToolSettings); + } + yield cake.runScript(scriptPath, cakeToolSettings, ...inputs.scriptArguments); } - yield cake.runScript(scriptPath, cakeToolSettings, ...inputs.scriptArguments); } catch (error) { if ((0, guards_1.isError)(error)) { diff --git a/src/action.ts b/src/action.ts index 61787e4..319a184 100644 --- a/src/action.ts +++ b/src/action.ts @@ -4,6 +4,7 @@ import * as input from './input'; interface CakeInputs { readonly scriptPath?: string, + readonly csprojPath?: string, readonly cakeVersion?: CakeVersion, readonly cakeBootstrap?: CakeBootstrap; } @@ -35,6 +36,7 @@ export type CakeBootstrap = export function getInputs(): CakeInputs & ScriptInputs { return { scriptPath: core.getInput('script-path'), + csprojPath: core.getInput('csproj-path'), cakeVersion: getCakeVersionInput(), cakeBootstrap: getCakeBootstrapInput(), scriptArguments: getScriptInputs() diff --git a/src/cake.ts b/src/cake.ts index 34e6400..5bf51e5 100644 --- a/src/cake.ts +++ b/src/cake.ts @@ -2,9 +2,11 @@ import { exec } from '@actions/exec'; import { which } from '@actions/io'; import { CakeToolSettings } from './cakeToolSettings'; import { CakeParameter } from './cakeParameter'; +import { ToolsDirectory } from './toolsDirectory'; const dotnetCake = 'dotnet-cake'; const dotnetLocalToolCake = 'dotnet tool run dotnet-cake'; +const dotnetRun = 'dotnet run'; export async function runScript( scriptPath = 'build.cake', @@ -20,6 +22,27 @@ export async function runScript( } } +export async function runProject( + csprojPath: string, + toolsDir: ToolsDirectory, + ...params: CakeParameter[] +) { + const cakeParams = formatParameters(params); + const exitCode = await exec(dotnetRun, [ + '--project', csprojPath, + '--no-launch-profile', + '--verbosity', 'minimal', + '--configuration', 'Release', + '--', + `--paths_tools="${toolsDir}"`, + ...cakeParams + ]); + + if (exitCode != 0) { + throw new Error(`Failed to run the csproj. Exit code: ${exitCode}`); + } +} + export async function bootstrapScript( scriptPath = 'build.cake', cakeToolSettings?: CakeToolSettings diff --git a/src/main.ts b/src/main.ts index 348cdf1..2793181 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,6 +11,7 @@ export async function run() { try { const inputs = action.getInputs(); const scriptPath = inputs.scriptPath; + const csprojPath = inputs.csprojPath; const version = inputs.cakeVersion; const bootstrap = inputs.cakeBootstrap; @@ -22,13 +23,18 @@ export async function run() { dotnet.disableTelemetry(); dotnet.disableWelcomeMessage(); - await cakeTool.install(toolsDir, version); + if (csprojPath) { + await cake.runProject(csprojPath, toolsDir, ...inputs.scriptArguments); + } else { + await cakeTool.install(toolsDir, version); - if (bootstrap === 'explicit') { - await cake.bootstrapScript(scriptPath, cakeToolSettings); + if (bootstrap === 'explicit') { + await cake.bootstrapScript(scriptPath, cakeToolSettings); + } + + await cake.runScript(scriptPath, cakeToolSettings, ...inputs.scriptArguments); } - await cake.runScript(scriptPath, cakeToolSettings, ...inputs.scriptArguments); } catch (error) { if (isError(error)) { core.setFailed(error.message);