diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 61328cd..6ffea84 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -153,3 +153,58 @@ jobs: string-parameter: 'value' numeric-parameter: 3 boolean-parameter: true + test-with-frosting: + name: Test with Cake Frosting + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, ubuntu-latest] + env: + project-directory: integrationtests/frosting + steps: + - name: Get the sources + uses: actions/checkout@v1 + - name: Install Node 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install the .NET 8 SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - name: Run a specific Cake Frosting project + uses: ./ + with: + project-path: ${{ env.project-directory}}/Build.csproj + - name: Run a specific target + uses: ./ + with: + project-path: ${{ env.project-directory}}/Build.csproj + target: Successful-Task + - name: Run with a specific verbosity level + uses: ./ + env: + EXPECTED_VERBOSITY: Diagnostic + with: + verbosity: Diagnostic + project-path: ${{ env.project-directory}}/Build.csproj + target: Test-Verbosity + - name: Do a dry run + uses: ./ + with: + dry-run: true + project-path: ${{ env.project-directory }}/Build.csproj + target: Test-Dry-Run + - name: Run with custom script parameters + uses: ./ + env: + EXPECTED_STRING_ARGUMENT: '''value''' + EXPECTED_NUMERIC_ARGUMENT: '3' + EXPECTED_BOOLEAN_ARGUMENT: 'true' + with: + project-path: ${{ env.project-directory }}/Build.csproj + target: Test-Script-Parameters + arguments: | + string-parameter: 'value' + numeric-parameter: 3 + boolean-parameter: true 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 54e7a5b..2a6cb73 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,13 +14,15 @@ 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/). You can also specify the path to your Cake script using the `script-path` option. If you are using a [Cake Frosting](https://cakebuild.net/docs/running-builds/runners/cake-frosting) project instead, you must specify the path to your `.csproj` file with the `project-path` parameter. + +All output from the Cake script or Cake Frosting project is automatically redirected to the build log for inspection. ## Inputs ### `script-path` -If your script is in another location, you can specify the path with the `script-path` [input parameter](https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepswith): +If your Cake script is located somewhere other than the root directory of your project, you can specify its path using the `script-path` [input parameter](https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepswith): ```yml steps: @@ -30,9 +32,21 @@ steps: script-path: path/to/script.cake ``` +### `project-path` + +If you are using [Cake Frosting](https://cakebuild.net/docs/running-builds/runners/cake-frosting), you must specify the path to the project file with the `project-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: + project-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,9 @@ 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 runs your script using the latest _stable_ version of the [Cake .NET Core Global tool](https://www.nuget.org/packages/Cake.Tool/). + +If you need to [use a specific version of Cake](https://cakebuild.net/docs/tutorials/pinning-cake-version) (e.g. for compatibility with older addins), you can specify it with the `cake-version` parameter: ```yml steps: @@ -98,7 +114,7 @@ steps: cake-version: 0.30.0 ``` -If you're pinning your Cake version using a [tool manifest file](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools#install-a-local-tool), then you can have the action restore any local tools, including Cake, by specifying `tool-manifest` as the argument for `cake-version`: +If you're pinning your Cake version using a [tool manifest file](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools#install-a-local-tool), you can have the action restore any local tools, including Cake, by specifying `tool-manifest` as the argument for `cake-version`: ```yml steps: @@ -108,11 +124,13 @@ steps: cake-version: tool-manifest ``` +> :information_source: This option is ignored when [using Cake Frosting projects](#project-path). + ### `cake-bootstrap` 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. -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`: +For older versions of Cake, you need to explicitly [bootstrap](https://cakebuild.net/docs/fundamentals/preprocessor-directives#module-directive) any referenced modules before running the script. The Cake action can handle this extra step for you by setting the `cake-bootstrap` parameter to `explicit`: ```yml steps: @@ -123,7 +141,7 @@ steps: cake-version: 0.38.5 ``` -If you're using Cake 1.0.0 or later and wish to opt out of the automatic bootstrapping of modules, you can do so by setting the `cake-bootstrap` parameter to `skip`: +If you're using Cake 1.0.0 or later and wish to opt out of the automatic bootstrapping of modules, you can set the `cake-bootstrap` parameter to `skip`: ```yml steps: @@ -133,11 +151,13 @@ steps: cake-bootstrap: skip ``` -The default value is `auto`, which means that the modules will be automatically bootstrapped on Cake 1.0.0 or later. +The default value is `auto`, which means modules will be automatically bootstrapped on Cake 1.0.0 or later. + +> :information_source: This option is ignored when [using Cake Frosting projects](#script-path). ## 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__/action.test.ts b/__tests__/action.test.ts index 2f366c1..7bff41b 100644 --- a/__tests__/action.test.ts +++ b/__tests__/action.test.ts @@ -5,19 +5,77 @@ import { CakeArgument, CakeSwitch } from '../src/cakeParameter'; jest.mock('@actions/core'); -describe('When getting the Cake input arguments from the action', () => { +describe('When getting the script-path input argument from the action', () => { const fakeGetInput = core.getInput as jest.MockedFunction; beforeAll(() => { when(fakeGetInput).calledWith('script-path').mockReturnValue('path/to/script.cake'); - when(fakeGetInput).calledWith('cake-version').mockReturnValue('the.version.number'); - when(fakeGetInput).calledWith('cake-bootstrap').mockReturnValue('auto'); + when(fakeGetInput).calledWith('project-path').mockReturnValue(''); + when(fakeGetInput).calledWith('cake-version').mockReturnValue(''); + when(fakeGetInput).calledWith('cake-bootstrap').mockReturnValue(''); when(fakeGetInput).calledWith('dry-run').mockReturnValue(''); when(fakeGetInput).calledWith('arguments').mockReturnValue(''); }); - test('it should return the argument for the script-path parameter', () => { - expect(action.getInputs().scriptPath).toBe('path/to/script.cake'); + test('it should return \'script\' as the build file type parameter', () => { + expect(action.getInputs().buildFile.type).toBe('script'); + }); + + test('it should return the argument for the script-path parameter as the build file path parameter', () => { + expect(action.getInputs().buildFile.path).toBe('path/to/script.cake'); + }); +}); + +describe('When getting the project-path input argument from the action', () => { + const fakeGetInput = core.getInput as jest.MockedFunction; + + beforeAll(() => { + when(fakeGetInput).calledWith('script-path').mockReturnValue(''); + when(fakeGetInput).calledWith('project-path').mockReturnValue('path/to/build.csproj'); + when(fakeGetInput).calledWith('cake-version').mockReturnValue(''); + when(fakeGetInput).calledWith('cake-bootstrap').mockReturnValue(''); + when(fakeGetInput).calledWith('dry-run').mockReturnValue(''); + when(fakeGetInput).calledWith('arguments').mockReturnValue(''); + }); + + test('it should return \'project\' as the build file type parameter', () => { + expect(action.getInputs().buildFile.type).toBe('project'); + }); + + test('it should return the argument for the project-path parameter as the build file path parameter', () => { + expect(action.getInputs().buildFile.path).toBe('path/to/build.csproj'); + }); +}); + +describe('When getting both the script-path and project-path input arguments from the action', () => { + const fakeGetInput = core.getInput as jest.MockedFunction; + + beforeAll(() => { + when(fakeGetInput).calledWith('script-path').mockReturnValue('path/to/build.cake'); + when(fakeGetInput).calledWith('project-path').mockReturnValue('path/to/build.csproj'); + when(fakeGetInput).calledWith('cake-version').mockReturnValue(''); + when(fakeGetInput).calledWith('cake-bootstrap').mockReturnValue(''); + when(fakeGetInput).calledWith('dry-run').mockReturnValue(''); + when(fakeGetInput).calledWith('arguments').mockReturnValue(''); + }); + + test('it should return \'project\' as the build file type parameter', () => { + expect(action.getInputs().buildFile.type).toBe('project'); + }); + + test('it should return the argument for the project-path parameter as the build file path parameter', () => { + expect(action.getInputs().buildFile.path).toBe('path/to/build.csproj'); + }); +}); + +describe('When getting the Cake tool input arguments from the action', () => { + const fakeGetInput = core.getInput as jest.MockedFunction; + + beforeAll(() => { + when(fakeGetInput).calledWith('cake-version').mockReturnValue('the.version.number'); + when(fakeGetInput).calledWith('cake-bootstrap').mockReturnValue('auto'); + when(fakeGetInput).calledWith('dry-run').mockReturnValue(''); + when(fakeGetInput).calledWith('arguments').mockReturnValue(''); }); test('it should return the argument for the cake-version parameter', () => { @@ -32,7 +90,7 @@ describe('When getting the Cake input arguments from the action', () => { }); }); -describe('When getting the documented script input arguments from the action', () => { +describe('When getting the Cake input arguments from the action', () => { const fakeGetInput = core.getInput as jest.MockedFunction; beforeAll(() => { @@ -43,15 +101,15 @@ describe('When getting the documented script input arguments from the action', ( }); test('it should return the argument for the target script parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('target', 'Task-To-Run')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('target', 'Task-To-Run')); }); test('it should return the argument for the verbosity script parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('verbosity', 'Verbosity-Level')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('verbosity', 'Verbosity-Level')); }); test('it should return the argument for the dry-run script parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeSwitch('dryrun')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeSwitch('dryrun')); }); }); @@ -64,7 +122,7 @@ describe('When getting the dry-run script input argument set to false from the a }); test('it should not pass the dry run switch to the script', () => { - expect(action.getInputs().scriptArguments).not.toContainEqual(new CakeSwitch('dryrun')); + expect(action.getInputs().buildArguments).not.toContainEqual(new CakeSwitch('dryrun')); }); }); @@ -80,15 +138,15 @@ describe('When getting multiple custom script input arguments from the action', }); test('it should return the argument for a custom string parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('string-parameter', '\'value\'')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('string-parameter', '\'value\'')); }); test('it should return the argument for a custom numeric parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('numeric-parameter', '3')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('numeric-parameter', '3')); }); test('it should return the argument for a custom boolean parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('boolean-parameter', 'true')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('boolean-parameter', 'true')); }); }); @@ -102,7 +160,7 @@ describe('When getting a single custom script input argument from the action', ( }); test('it should return the argument for the custom parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('name', 'value')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('name', 'value')); }); }); @@ -114,7 +172,7 @@ describe('When getting a single custom script input argument on one line from th }); test('it should return the argument for the custom parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('name', 'value')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('name', 'value')); }); }); @@ -128,7 +186,7 @@ describe('When getting a custom script input argument that contains colons (e.g. }); test('it should return the argument for the custom parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('url', 'https://example.com')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('url', 'https://example.com')); }); }); @@ -150,11 +208,11 @@ describe('When getting improperly formatted custom script input arguments from t }); test('it should not parse the invalid parameter names and values', () => { - expect(action.getInputs().scriptArguments).not.toContainEqual(new CakeArgument('name', 'value')); + expect(action.getInputs().buildArguments).not.toContainEqual(new CakeArgument('name', 'value')); }); test('it should not parse the invalid parameter names', () => { - expect(action.getInputs().scriptArguments).not.toContainEqual(new CakeArgument('name', '')); + expect(action.getInputs().buildArguments).not.toContainEqual(new CakeArgument('name', '')); }); }); @@ -163,6 +221,7 @@ describe('When getting no input arguments from the action', () => { beforeAll(() => { when(fakeGetInput).calledWith('script-path').mockReturnValue(''); + when(fakeGetInput).calledWith('project-path').mockReturnValue(''); when(fakeGetInput).calledWith('cake-version').mockReturnValue(''); when(fakeGetInput).calledWith('cake-bootstrap').mockReturnValue(''); when(fakeGetInput).calledWith('target').mockReturnValue(''); @@ -171,8 +230,12 @@ describe('When getting no input arguments from the action', () => { when(fakeGetInput).calledWith('arguments').mockReturnValue(''); }); - test('it should return an empty string for the script-path parameter', () => { - expect(action.getInputs().scriptPath).toBe(''); + test('it should return \'script\' as the build file type parameter', () => { + expect(action.getInputs().buildFile.type).toBe('script'); + }); + + test('it should return \'build.cake\' as the build file path parameter', () => { + expect(action.getInputs().buildFile.path).toBe('build.cake'); }); test('it should return latest for the cake-version parameter', () => { @@ -184,15 +247,15 @@ describe('When getting no input arguments from the action', () => { }); test('it should return an empty string for the target script parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('target', '')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('target', '')); }); test('it should return an empty string for the verbosity script parameter', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeArgument('verbosity', '')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeArgument('verbosity', '')); }); test('it should not pass the dry run switch to the script', () => { - expect(action.getInputs().scriptArguments).not.toContainEqual(new CakeSwitch('dryrun')); + expect(action.getInputs().buildArguments).not.toContainEqual(new CakeSwitch('dryrun')); }); }); @@ -232,7 +295,7 @@ describe('When getting the cake-bootstrap script input argument set to auto from }); test('it should not pass the skip-bootstrap switch to the script', () => { - expect(action.getInputs().scriptArguments).not.toContainEqual(new CakeSwitch('skip-bootstrap')); + expect(action.getInputs().buildArguments).not.toContainEqual(new CakeSwitch('skip-bootstrap')); }); }); @@ -248,7 +311,7 @@ describe('When getting the cake-bootstrap script input argument set to explicit }); test('it should not pass the skip-bootstrap switch to the script', () => { - expect(action.getInputs().scriptArguments).not.toContainEqual(new CakeSwitch('skip-bootstrap')); + expect(action.getInputs().buildArguments).not.toContainEqual(new CakeSwitch('skip-bootstrap')); }); }); @@ -264,6 +327,6 @@ describe('When getting the cake-bootstrap script input argument set to skip from }); test('it should pass the skip-bootstrap switch to the script', () => { - expect(action.getInputs().scriptArguments).toContainEqual(new CakeSwitch('skip-bootstrap')); + expect(action.getInputs().buildArguments).toContainEqual(new CakeSwitch('skip-bootstrap')); }); }); 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..898c431 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -20,7 +20,8 @@ describe('When running the action without any input arguments', () => { beforeAll(() => { fakeGetInputs.mockReturnValue({ - scriptArguments: [] + buildFile: { type: 'script', path: 'build.cake' }, + buildArguments: [] }); }); @@ -56,8 +57,8 @@ describe('When running the action with the script path input argument', () => { beforeAll(() => { fakeGetInputs.mockReturnValue({ - scriptPath: 'path/to/script.cake', - scriptArguments: [] + buildFile: { type: 'script', path: 'path/to/script.cake' }, + buildArguments: [] }); }); @@ -67,14 +68,37 @@ 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({ + buildFile: { type: 'project', path: 'path/to/build.csproj' }, + buildArguments: [] + }); + }); + + 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; beforeAll(() => { fakeGetInputs.mockReturnValue({ + buildFile: { type: 'script', path: 'build.cake' }, cakeVersion: { version: 'tool-manifest' }, - scriptArguments: [] + buildArguments: [] }); }); @@ -90,8 +114,9 @@ describe('When running the action with latest as the Cake version input argument beforeAll(() => { fakeGetInputs.mockReturnValue({ + buildFile: { type: 'script', path: 'build.cake' }, cakeVersion: { version: 'latest' }, - scriptArguments: [] + buildArguments: [] }); }); @@ -107,8 +132,9 @@ describe('When running the action with a specific version as the Cake version in beforeAll(() => { fakeGetInputs.mockReturnValue({ + buildFile: { type: 'script', path: 'build.cake' }, cakeVersion: { version: 'specific', number: 'the.version.number' }, - scriptArguments: [] + buildArguments: [] }); }); @@ -127,8 +153,9 @@ describe('When running the action with auto as the Cake bootstrap input argument beforeAll(() => { fakeGetInputs.mockReturnValue({ + buildFile: { type: 'script', path: 'build.cake' }, cakeBootstrap: 'auto', - scriptArguments: [] + buildArguments: [] }); }); @@ -144,9 +171,9 @@ describe('When running the action with explicit as the Cake bootstrap input argu beforeAll(() => { fakeGetInputs.mockReturnValue({ - scriptPath: 'custom.cake', + buildFile: { type: 'script', path: 'custom.cake' }, cakeBootstrap: 'explicit', - scriptArguments: [] + buildArguments: [] }); }); @@ -162,8 +189,9 @@ describe('When running the action with skip as the Cake bootstrap input argument beforeAll(() => { fakeGetInputs.mockReturnValue({ + buildFile: { type: 'script', path: 'build.cake' }, cakeBootstrap: 'skip', - scriptArguments: [] + buildArguments: [] }); }); @@ -179,7 +207,8 @@ describe('When running the action with the target input argument', () => { beforeAll(() => { fakeGetInputs.mockReturnValue({ - scriptArguments: [new CakeArgument('target', 'Task-To-Run')] + buildFile: { type: 'script', path: 'build.cake' }, + buildArguments: [new CakeArgument('target', 'Task-To-Run')] }); }); @@ -196,7 +225,8 @@ describe('When running the action with the verbosity input argument', () => { beforeAll(() => { fakeGetInputs.mockReturnValue({ - scriptArguments: [new CakeArgument('verbosity', 'Verbosity-Level')] + buildFile: { type: 'script', path: 'build.cake' }, + buildArguments: [new CakeArgument('verbosity', 'Verbosity-Level')] }); }); @@ -213,7 +243,8 @@ describe('When running the action with custom script input arguments', () => { beforeAll(() => { fakeGetInputs.mockReturnValue({ - scriptArguments: [ + buildFile: { type: 'script', path: 'build.cake' }, + buildArguments: [ new CakeArgument('string-parameter', '\'value\''), new CakeArgument('numeric-parameter', '3'), new CakeArgument('boolean-parameter', 'true'), diff --git a/action.yml b/action.yml index ff9a130..c3c0539 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' + project-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..575b8d1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3986,17 +3986,34 @@ var __importStar = (this && this.__importStar) || function (mod) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getInputs = void 0; const core = __importStar(__nccwpck_require__(2186)); -const script = __importStar(__nccwpck_require__(8714)); +const build = __importStar(__nccwpck_require__(8714)); const input = __importStar(__nccwpck_require__(6747)); function getInputs() { return { - scriptPath: core.getInput('script-path'), + buildFile: getFileInput(), cakeVersion: getCakeVersionInput(), cakeBootstrap: getCakeBootstrapInput(), - scriptArguments: getScriptInputs() + buildArguments: getScriptInputs() }; } exports.getInputs = getInputs; +function getFileInput() { + const scriptPath = core.getInput('script-path'); + const projectPath = core.getInput('project-path'); + // When both script and project paths are specified, + // the project path takes precedence. + // If neither is provided, the default 'build.cake' script + // is used, as per Cake's convention. + if (projectPath) { + return { type: 'project', path: projectPath }; + } + else if (scriptPath) { + return { type: 'script', path: scriptPath }; + } + else { + return { type: 'script', path: 'build.cake' }; + } +} function getCakeVersionInput() { const version = core.getInput('cake-version').toLowerCase(); switch (version) { @@ -4020,8 +4037,8 @@ function getCakeBootstrapInput() { } function getScriptInputs() { return [ - new script.CakeArgument('target', core.getInput('target')), - new script.CakeArgument('verbosity', core.getInput('verbosity')), + new build.CakeArgument('target', core.getInput('target')), + new build.CakeArgument('verbosity', core.getInput('verbosity')), ...parseSkipBootstrapSwitch(), ...parseDryRunSwitch(), ...parseCustomArguments() @@ -4029,19 +4046,19 @@ function getScriptInputs() { } function parseSkipBootstrapSwitch() { return getCakeBootstrapInput() === 'skip' - ? [new script.CakeSwitch('skip-bootstrap')] + ? [new build.CakeSwitch('skip-bootstrap')] : []; } function parseDryRunSwitch() { return input.getBooleanInput('dry-run') - ? [new script.CakeSwitch('dryrun')] + ? [new build.CakeSwitch('dryrun')] : []; } function parseCustomArguments() { return input.getMultilineInput('arguments') .filter(line => containsArgumentDefinition(line)) .map(line => parseNameAndValue(line)) - .map(([name, value]) => new script.CakeArgument(name, value)); + .map(([name, value]) => new build.CakeArgument(name, value)); } function containsArgumentDefinition(line) { return /.+:.+/.test(line); @@ -4070,11 +4087,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 +4104,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); @@ -4398,6 +4434,74 @@ function restoreLocalTools() { exports.restoreLocalTools = restoreLocalTools; +/***/ }), + +/***/ 5047: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.script = exports.project = void 0; +const cakeToolSettings_1 = __nccwpck_require__(6881); +const toolsDirectory_1 = __nccwpck_require__(6745); +const cake = __importStar(__nccwpck_require__(9275)); +const cakeTool = __importStar(__nccwpck_require__(4574)); +function project(path, ...params) { + return __awaiter(this, void 0, void 0, function* () { + const toolsDir = new toolsDirectory_1.ToolsDirectory(); + toolsDir.create(); + yield cake.runProject(path, toolsDir, ...params); + }); +} +exports.project = project; +function script(path, version, bootstrap, ...params) { + return __awaiter(this, void 0, void 0, function* () { + const toolsDir = new toolsDirectory_1.ToolsDirectory(); + toolsDir.create(); + const cakeToolSettings = new cakeToolSettings_1.CakeToolSettings(toolsDir, (version === null || version === void 0 ? void 0 : version.version) === 'tool-manifest'); + yield cakeTool.install(toolsDir, version); + if (bootstrap === 'explicit') { + yield cake.bootstrapScript(path, cakeToolSettings); + } + yield cake.runScript(path, cakeToolSettings, ...params); + }); +} +exports.script = script; + + /***/ }), /***/ 3265: @@ -4503,30 +4607,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", ({ value: true })); exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); -const toolsDirectory_1 = __nccwpck_require__(6745); -const cakeToolSettings_1 = __nccwpck_require__(6881); -const guards_1 = __nccwpck_require__(3265); -const dotnet = __importStar(__nccwpck_require__(9870)); -const cakeTool = __importStar(__nccwpck_require__(4574)); -const cake = __importStar(__nccwpck_require__(9275)); const action = __importStar(__nccwpck_require__(7672)); +const dotnet = __importStar(__nccwpck_require__(9870)); +const exec = __importStar(__nccwpck_require__(5047)); +const guards_1 = __nccwpck_require__(3265); function run() { return __awaiter(this, void 0, void 0, function* () { try { const inputs = action.getInputs(); - const scriptPath = inputs.scriptPath; + const buildFile = inputs.buildFile; const version = inputs.cakeVersion; const bootstrap = inputs.cakeBootstrap; - const toolsDir = new toolsDirectory_1.ToolsDirectory(); - toolsDir.create(); - 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); + switch (buildFile.type) { + case 'project': + yield exec.project(buildFile.path, ...inputs.buildArguments); + break; + case 'script': { + yield exec.script(buildFile.path, version, bootstrap, ...inputs.buildArguments); + break; + } } - yield cake.runScript(scriptPath, cakeToolSettings, ...inputs.scriptArguments); } catch (error) { if ((0, guards_1.isError)(error)) { diff --git a/integrationtests/frosting/Build.csproj b/integrationtests/frosting/Build.csproj new file mode 100644 index 0000000..8f8fbc7 --- /dev/null +++ b/integrationtests/frosting/Build.csproj @@ -0,0 +1,10 @@ + + + Exe + net8.0 + $(MSBuildProjectDirectory) + + + + + diff --git a/integrationtests/frosting/Program.cs b/integrationtests/frosting/Program.cs new file mode 100644 index 0000000..6438d7c --- /dev/null +++ b/integrationtests/frosting/Program.cs @@ -0,0 +1,139 @@ +using System; +using Cake.Common; +using Cake.Core; +using Cake.Core.Diagnostics; +using Cake.Frosting; + +public static class Program +{ + public static int Main(string[] args) + { + return new CakeHost() + .UseContext() + .Run(args); + } +} + +public class BuildContext : FrostingContext +{ + public BuildContext(ICakeContext context) + : base(context) + { + StringParameter = context.Argument("String-Parameter", null); + NumericParameter = context.Argument("Numeric-Parameter", null); + BooleanParameter = context.Argument("Boolean-Parameter", null); + } + + public string StringParameter { get; } + + public int? NumericParameter { get; } + + public bool? BooleanParameter { get; } + +} + +[TaskName("Successful-Task")] +public sealed class SuccessfulTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.Log.Information("✓ Passed"); + } +} + +[TaskName("Test-Verbosity")] +public sealed class TestVerbosity : FrostingTask +{ + public override void Run(BuildContext context) + { + var hasExpectedVerbosity = Enum.TryParse( + context.EnvironmentVariable("EXPECTED_VERBOSITY"), + ignoreCase: true, + out Verbosity expectedVerbosity); + + if (!hasExpectedVerbosity) + { + throw new Exception( + "✕ The EXPECTED_VERBOSITY environment variable is not set or it doesn't contain a verbosity level"); + } + + var actualVerbosity = context.Log.Verbosity; + + if (expectedVerbosity != actualVerbosity) + { + throw new Exception($"✕ Expected verbosity {expectedVerbosity} but got {actualVerbosity}"); + } + + context.Log.Information("✓ Passed"); + } +} + +[TaskName("Test-Dry-Run")] +public sealed class TestDryRun : FrostingTask +{ + public override void Run(BuildContext context) + { + if (!context.IsDryRun()) + { + throw new Exception("✕ Expected this to be a dry run, but it isn't"); + } + + context.Log.Information("✓ Passed"); + } +} + +[TaskName("Test-Script-Parameters")] +public sealed class TestScriptParameters : FrostingTask +{ + public override void Run(BuildContext context) + { + var expectedStringArgument = context.EnvironmentVariable("EXPECTED_STRING_ARGUMENT"); + + var hasExpectedNumericArgument = int.TryParse( + context.EnvironmentVariable("EXPECTED_NUMERIC_ARGUMENT"), + out int expectedNumericArgument); + + var hasExpectedBooleanArgument = bool.TryParse( + context.EnvironmentVariable("EXPECTED_BOOLEAN_ARGUMENT"), + out bool expectedBooleanArgument); + + if (string.IsNullOrEmpty(expectedStringArgument)) + { + throw new Exception( + "✕ The EXPECTED_STRING_ARGUMENT environment variable is not set"); + } + + if (!hasExpectedNumericArgument) + { + throw new Exception( + "✕ The EXPECTED_NUMERIC_ARGUMENT environment variable is not set"); + } + + if (!hasExpectedBooleanArgument) + { + throw new Exception( + "✕ The EXPECTED_BOOLEAN_ARGUMENT environment variable is not set"); + } + + if (expectedStringArgument != context.StringParameter) + { + throw new Exception($"✕ Expected string argument {expectedStringArgument} but got {context.StringParameter}"); + } + + if (expectedNumericArgument != context.NumericParameter) + { + throw new Exception($"✕ Expected numeric argument {expectedNumericArgument} but got {context.NumericParameter}"); + } + + if (expectedBooleanArgument != context.BooleanParameter) + { + throw new Exception($"✕ Expected boolean argument {expectedBooleanArgument} but got {context.BooleanParameter}"); + } + + context.Log.Information("✓ Passed"); + } +} + +[TaskName("Default")] +[IsDependentOn(typeof(SuccessfulTask))] +public class DefaultTask : FrostingTask; diff --git a/src/action.ts b/src/action.ts index 61787e4..0f726d6 100644 --- a/src/action.ts +++ b/src/action.ts @@ -1,46 +1,73 @@ import * as core from '@actions/core'; -import * as script from './cakeParameter'; +import * as build from './cakeParameter'; import * as input from './input'; interface CakeInputs { - readonly scriptPath?: string, + readonly buildFile: BuildFile, readonly cakeVersion?: CakeVersion, readonly cakeBootstrap?: CakeBootstrap; } -interface ScriptInputs { - readonly scriptArguments: script.CakeParameter[]; +interface BuildInputs { + readonly buildArguments: build.CakeParameter[]; } +export type BuildFile = Script | Project; +type Script = { + readonly type: 'script', + path: string; +}; +type Project = { + readonly type: 'project', + path: string; +}; + export type CakeVersion = | ToolManifest | Latest | Specific; type ToolManifest = { - version: 'tool-manifest'; + readonly version: 'tool-manifest'; }; type Latest = { - version: 'latest'; + readonly version: 'latest'; }; type Specific = { - version: 'specific', + readonly version: 'specific', number: string; }; export type CakeBootstrap = | 'auto' | 'explicit' - | 'skip' + | 'skip'; -export function getInputs(): CakeInputs & ScriptInputs { +export function getInputs(): CakeInputs & BuildInputs { return { - scriptPath: core.getInput('script-path'), + buildFile: getFileInput(), cakeVersion: getCakeVersionInput(), cakeBootstrap: getCakeBootstrapInput(), - scriptArguments: getScriptInputs() + buildArguments: getScriptInputs() }; } +function getFileInput(): BuildFile { + const scriptPath = core.getInput('script-path'); + const projectPath = core.getInput('project-path'); + + // When both script and project paths are specified, + // the project path takes precedence. + // If neither is provided, the default 'build.cake' script + // is used, as per Cake's convention. + if (projectPath) { + return { type: 'project', path: projectPath }; + } else if (scriptPath) { + return { type: 'script', path: scriptPath }; + } else { + return { type: 'script', path: 'build.cake' }; + } +} + function getCakeVersionInput(): CakeVersion { const version = core.getInput('cake-version').toLowerCase(); switch (version) { @@ -64,33 +91,33 @@ function getCakeBootstrapInput(): CakeBootstrap { } } -function getScriptInputs(): script.CakeParameter[] { +function getScriptInputs(): build.CakeParameter[] { return [ - new script.CakeArgument('target', core.getInput('target')), - new script.CakeArgument('verbosity', core.getInput('verbosity')), + new build.CakeArgument('target', core.getInput('target')), + new build.CakeArgument('verbosity', core.getInput('verbosity')), ...parseSkipBootstrapSwitch(), ...parseDryRunSwitch(), ...parseCustomArguments() ]; } -function parseSkipBootstrapSwitch() : script.CakeParameter[] { +function parseSkipBootstrapSwitch(): build.CakeParameter[] { return getCakeBootstrapInput() === 'skip' - ? [new script.CakeSwitch('skip-bootstrap')] + ? [new build.CakeSwitch('skip-bootstrap')] : []; } -function parseDryRunSwitch(): script.CakeParameter[] { +function parseDryRunSwitch(): build.CakeParameter[] { return input.getBooleanInput('dry-run') - ? [new script.CakeSwitch('dryrun')] + ? [new build.CakeSwitch('dryrun')] : []; } -function parseCustomArguments(): script.CakeParameter[] { +function parseCustomArguments(): build.CakeParameter[] { return input.getMultilineInput('arguments') .filter(line => containsArgumentDefinition(line)) .map(line => parseNameAndValue(line)) - .map(([name, value]) => new script.CakeArgument(name, value)); + .map(([name, value]) => new build.CakeArgument(name, value)); } function containsArgumentDefinition(line: string): boolean { 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/exec.ts b/src/exec.ts new file mode 100644 index 0000000..ff4f1f1 --- /dev/null +++ b/src/exec.ts @@ -0,0 +1,30 @@ +import { CakeBootstrap, CakeVersion } from './action'; +import { CakeParameter } from './cakeParameter'; +import { CakeToolSettings } from './cakeToolSettings'; +import { ToolsDirectory } from './toolsDirectory'; +import * as cake from './cake'; +import * as cakeTool from './cakeTool'; + +export async function project(path: string, ...params: CakeParameter[]) { + const toolsDir = new ToolsDirectory(); + toolsDir.create(); + await cake.runProject(path, toolsDir, ...params); +} + +export async function script( + path: string, + version?: CakeVersion, + bootstrap?: CakeBootstrap, + ...params: CakeParameter[]) { + const toolsDir = new ToolsDirectory(); + const cakeToolSettings = new CakeToolSettings(toolsDir, version?.version === 'tool-manifest'); + + toolsDir.create(); + await cakeTool.install(toolsDir, version); + + if (bootstrap === 'explicit') { + await cake.bootstrapScript(path, cakeToolSettings); + } + + await cake.runScript(path, cakeToolSettings, ...params); +} diff --git a/src/main.ts b/src/main.ts index 348cdf1..631d390 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,34 +1,28 @@ import * as core from '@actions/core'; -import { ToolsDirectory } from './toolsDirectory'; -import { CakeToolSettings } from './cakeToolSettings'; -import { isError, isString } from './guards'; -import * as dotnet from './dotnet'; -import * as cakeTool from './cakeTool'; -import * as cake from './cake'; import * as action from './action'; +import * as dotnet from './dotnet'; +import * as exec from './exec'; +import { isError, isString } from './guards'; export async function run() { try { const inputs = action.getInputs(); - const scriptPath = inputs.scriptPath; + const buildFile = inputs.buildFile; const version = inputs.cakeVersion; const bootstrap = inputs.cakeBootstrap; - const toolsDir = new ToolsDirectory(); - toolsDir.create(); - - const cakeToolSettings = new CakeToolSettings(toolsDir, version?.version === 'tool-manifest'); - dotnet.disableTelemetry(); dotnet.disableWelcomeMessage(); - await cakeTool.install(toolsDir, version); - - if (bootstrap === 'explicit') { - await cake.bootstrapScript(scriptPath, cakeToolSettings); + switch (buildFile.type) { + case 'project': + await exec.project(buildFile.path, ...inputs.buildArguments); + break; + case 'script': { + await exec.script(buildFile.path, version, bootstrap, ...inputs.buildArguments); + break; + } } - - await cake.runScript(scriptPath, cakeToolSettings, ...inputs.scriptArguments); } catch (error) { if (isError(error)) { core.setFailed(error.message);