diff --git a/.appveyor.yml b/.appveyor.yml index f2c64937d..5eec94f17 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,6 +8,9 @@ environment: #---------------------------------# image: Visual Studio 2022 +init: + - git config --global core.autocrlf true + #---------------------------------# # Install .NET # #---------------------------------# @@ -16,9 +19,9 @@ install: - ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null - ps: Invoke-WebRequest -Uri "https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.ps1" -OutFile "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 5.0.408 -InstallDir $env:DOTNET_INSTALL_DIR' - - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 6.0.419 -InstallDir $env:DOTNET_INSTALL_DIR' - - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 7.0.406 -InstallDir $env:DOTNET_INSTALL_DIR' - - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 8.0.201 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 6.0.421 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 7.0.408 -InstallDir $env:DOTNET_INSTALL_DIR' + - ps: '& "$($env:DOTNET_INSTALL_DIR)/dotnet-install.ps1" -Version 8.0.204 -InstallDir $env:DOTNET_INSTALL_DIR' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" - ps: dotnet --info diff --git a/.azuredevops/pipelines/templates/steps/install-markdownlint.yml b/.azuredevops/pipelines/templates/steps/install-markdownlint.yml new file mode 100644 index 000000000..ed4e33b1e --- /dev/null +++ b/.azuredevops/pipelines/templates/steps/install-markdownlint.yml @@ -0,0 +1,9 @@ +# Installs markdownlint + +steps: + - task: NodeTool@0 + inputs: + versionSpec: '20.x' + displayName: 'Install NodeJs 20.x' + - script: npm install -g markdownlint-cli + displayName: 'Install markdownlint' diff --git a/.azuredevops/pipelines/templates/steps/install-net5.yml b/.azuredevops/pipelines/templates/steps/install-net5.yml new file mode 100644 index 000000000..739dff075 --- /dev/null +++ b/.azuredevops/pipelines/templates/steps/install-net5.yml @@ -0,0 +1,7 @@ +# Installs .NET 6 + +steps: + - task: UseDotNet@2 + inputs: + version: '5.x' + displayName: 'Install .NET 5' diff --git a/.azuredevops/pipelines/templates/steps/install-net6.yml b/.azuredevops/pipelines/templates/steps/install-net6.yml new file mode 100644 index 000000000..24988ad50 --- /dev/null +++ b/.azuredevops/pipelines/templates/steps/install-net6.yml @@ -0,0 +1,7 @@ +# Installs .NET 6 + +steps: + - task: UseDotNet@2 + inputs: + version: '6.x' + displayName: 'Install .NET 6' diff --git a/.azuredevops/pipelines/templates/steps/install-net7.yml b/.azuredevops/pipelines/templates/steps/install-net7.yml new file mode 100644 index 000000000..e7fc55a11 --- /dev/null +++ b/.azuredevops/pipelines/templates/steps/install-net7.yml @@ -0,0 +1,7 @@ +# Installs .NET 6 + +steps: + - task: UseDotNet@2 + inputs: + version: '7.x' + displayName: 'Install .NET 7' diff --git a/.azuredevops/pipelines/templates/steps/install-net8.yml b/.azuredevops/pipelines/templates/steps/install-net8.yml new file mode 100644 index 000000000..d89b6bc5a --- /dev/null +++ b/.azuredevops/pipelines/templates/steps/install-net8.yml @@ -0,0 +1,7 @@ +# Installs .NET 6 + +steps: + - task: UseDotNet@2 + inputs: + version: '8.x' + displayName: 'Install .NET 8' diff --git a/.azuredevops/pipelines/templates/steps/install-required-dotnet-versions-for-building.yml b/.azuredevops/pipelines/templates/steps/install-required-dotnet-versions-for-building.yml index 9dfa6aae1..8cc717f40 100644 --- a/.azuredevops/pipelines/templates/steps/install-required-dotnet-versions-for-building.yml +++ b/.azuredevops/pipelines/templates/steps/install-required-dotnet-versions-for-building.yml @@ -2,19 +2,7 @@ steps: # .NET 5 required for GitVersion - - task: UseDotNet@2 - inputs: - version: '5.x' - displayName: 'Install .NET 5' - - task: UseDotNet@2 - inputs: - version: '6.x' - displayName: 'Install .NET 6' - - task: UseDotNet@2 - inputs: - version: '7.x' - displayName: 'Install .NET 7' - - task: UseDotNet@2 - inputs: - version: '8.x' - displayName: 'Install .NET 8' + - template: install-net5.yml + - template: install-net6.yml + - template: install-net7.yml + - template: install-net8.yml diff --git a/.azuredevops/pipelines/templates/steps/provide-nuget-packages.yml b/.azuredevops/pipelines/templates/steps/provide-nuget-packages.yml new file mode 100644 index 000000000..70b50d214 --- /dev/null +++ b/.azuredevops/pipelines/templates/steps/provide-nuget-packages.yml @@ -0,0 +1,11 @@ +# Makes NuGet packages available for testing + +steps: + - download: current + artifact: NuGet Package + displayName: 'Download build artifact' + - task: CopyFiles@2 + inputs: + sourceFolder: $(Pipeline.Workspace)/NuGet Package + targetFolder: $(Build.SourcesDirectory)/BuildArtifacts/Packages/NuGet + displayName: 'Copy build artifact for test run' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..9292494e8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,68 @@ +name: Build and tests + +# Workflow Trigger +on: + # Trigger the workflow on a pull request to any branch + pull_request: + # Triggers the workflow in the event there is a push to master + push: + branches: + - master + +jobs: + # Build + Build: + name: Build + runs-on: ubuntu-22.04 + steps: + - name: Get the sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - name: Fetch all tags and branches + run: git fetch --prune --unshallow + - name: Install .NET + uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4 + with: + # .NET 5 required for GitVersion + dotnet-version: | + 5.x + 6.x + 7.x + 8.x + - name: Build + run: ./build.sh + shell: bash + - name: Publish NuGet package as build artifact + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4 + with: + name: NuGet Package + path: ./BuildArtifacts/Packages/NuGet/ + # Integration Tests Cake.Issues.PullRequests.GitHubActions Cake Scripting + IntegrationTestsPullRequestsGitHubActionsCakeScripting: + name: Integration Tests Cake.Issues.PullRequests.GitHubActions Cake Scripting + needs: Build + strategy: + fail-fast: false + matrix: + os: [ + windows-2019, windows-2022, + # Disabled until https://github.com/cake-contrib/Cake.Issues/issues/514 is fixed + # ubuntu-20.04, ubuntu-22.04, + macos-11, macos-14] + dotnet: [6.x, 7.x, 8.x] + runs-on: ${{ matrix.os }} + steps: + - name: Get the sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - name: Download build artifact + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4 + with: + name: NuGet Package + path: ./BuildArtifacts/Packages/NuGet + - name: Install .NET + uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4 + with: + dotnet-version: ${{ matrix.dotnet }} + - name: Run integration tests + run: ./build.sh --verbosity=diagnostic + working-directory: ./tests/Cake.Issues.PullRequests.GitHubActions/script-runner/ + shell: bash diff --git a/CiStatus.md b/CiStatus.md index 3a76a5781..dc4a26fb4 100644 --- a/CiStatus.md +++ b/CiStatus.md @@ -1,6 +1,6 @@ # Build & Test Status -## Build / Unit Tests +## Build / Tests | CI Server | Runner | Operating System | Develop | Master | |:--:|:--:|:--:|:--:|:--:| @@ -8,6 +8,18 @@ |Azure Pipelines|N/A|Windows|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&jobName=Build%20%26%20Unit%20Tests&configuration=Build%20%26%20Unit%20Tests%20Windows)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&jobName=Build%20%26%20Unit%20Tests&configuration=Build%20%26%20Unit%20Tests%20Windows)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| |Azure Pipelines|N/A|Ubuntu|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&jobName=Build%20%26%20Unit%20Tests&configuration=Build%20%26%20Unit%20Tests%20Ubuntu)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&jobName=Build%20%26%20Unit%20Tests&configuration=Build%20%26%20Unit%20Tests%20Ubuntu)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| |Azure Pipelines|N/A|macOS|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&jobName=Build%20%26%20Unit%20Tests&configuration=Build%20%26%20Unit%20Tests%20macOS)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&jobName=Build%20%26%20Unit%20Tests&configuration=Build%20%26%20Unit%20Tests%20macOS)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|GitHub Actions|N/A|Ubuntu|[![Build and tests](https://github.com/cake-contrib/Cake.Issues/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/cake-contrib/Cake.Issues/actions/workflows/build.yml)|[![Build and tests](https://github.com/cake-contrib/Cake.Issues/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/cake-contrib/Cake.Issues/actions/workflows/build.yml)| + +## Integration Tests Cake.Issues.GitRepository + +| CI Server | Runner | Operating System | Develop | Master | +|:--:|:--:|:--:|:--:|:--:| +|Azure Pipelines|Cake Scripting|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.GitRepository&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| ## Integration Tests Cake.Issues.Markdownlint @@ -19,3 +31,66 @@ |Azure Pipelines|Cake Scripting|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Markdownlint&jobName=Test&configuration=Test%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Markdownlint&jobName=Test&configuration=Test%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| |Azure Pipelines|Cake Scripting|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Markdownlint&jobName=Test&configuration=Test%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Markdownlint&jobName=Test&configuration=Test%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| |Azure Pipelines|Cake Scripting|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Markdownlint&jobName=Test&configuration=Test%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Markdownlint&jobName=Test&configuration=Test%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| + +## Integration Tests Cake.Issues.Reporting.Console + +| CI Server | Runner | Operating System | Develop | Master | +|:--:|:--:|:--:|:--:|:--:| +|Azure Pipelines|Cake Scripting|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Console&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| + +## Integration Tests Cake.Issues.Reporting.Generic + +| CI Server | Runner | Operating System | Develop | Master | +|:--:|:--:|:--:|:--:|:--:| +|Azure Pipelines|Cake Scripting|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Generic&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| + +## Integration Tests Cake.Issues.Reporting.Sarif + +| CI Server | Runner | Operating System | Develop | Master | +|:--:|:--:|:--:|:--:|:--:| +|Azure Pipelines|Cake Scripting|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Scripting|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Scripting&configuration=Test%20Cake%20Scripting%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 6|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%206&configuration=Test%20Cake%20Frosting%20.NET%206%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 7|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 7|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 7|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 7|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 7|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 7|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%207&configuration=Test%20Cake%20Frosting%20.NET%207%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 8|Windows Server 2019|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Windows_Server_2019)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 8|Windows Server 2022|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Windows_Server_2022)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 8|macOS 11|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20macOS_11)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 8|macOS 13|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20macOS_13)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 8|Ubuntu 20.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Ubuntu_20_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| +|Azure Pipelines|Cake Frosting .NET 8|Ubuntu 22.04|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=develop&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=develop)|[![Build Status](https://dev.azure.com/cake-contrib/Cake.Issues/_apis/build/status%2Fcake-contrib.Cake.Issues?branchName=master&stageName=Integration%20Tests%20Cake.Issues.Reporting.Sarif&jobName=Test%20Cake%20Frosting%20.NET%208&configuration=Test%20Cake%20Frosting%20.NET%208%20Ubuntu_22_04)](https://dev.azure.com/cake-contrib/Cake.Issues/_build/latest?definitionId=2&branchName=master)| diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml index 721c1ba4d..f5d7620c1 100644 --- a/GitReleaseManager.yaml +++ b/GitReleaseManager.yaml @@ -3,6 +3,7 @@ issue-labels-include: - Feature - Bug - Improvement +- Dependencies - Documentation issue-labels-exclude: - Build diff --git a/LICENSE b/LICENSE index 1b9b8d618..1dbb12432 100644 --- a/LICENSE +++ b/LICENSE @@ -24,9 +24,22 @@ SOFTWARE. The binary distribution of Cake.Issues.MsBuild on nuget.org incorporates material from the projects listed below: +1. MSBuild.StructuredLogger +2. Microsoft.Build.Framework & Microsoft.Build.Utilities.Core +3. System.Collections.Immutable + +Cake.Issues.Reporting.Generic incorporates material from the projects listed below: + +4. LitJSON + +The binary distribution of Cake.Issues.Reporting.Generic on nuget.org incorporates material from the projects listed below: + +5. Gazorator +6. ASP.NET Core + --- -MSBuild.StructuredLogger +1. MSBuild.StructuredLogger The MIT License (MIT) @@ -52,7 +65,7 @@ SOFTWARE. --- -Microsoft.Build.Framework & Microsoft.Build.Utilities.Core +2. Microsoft.Build.Framework & Microsoft.Build.Utilities.Core MICROSOFT SOFTWARE LICENSE TERMS @@ -155,7 +168,95 @@ EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous po --- -System.Collections.Immutable +3. System.Collections.Immutable + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +4. LitJSON + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +Thank you for reading this notice. Following the tradition of other public +domain projects, here's a blessing: + + May you find forgiveness for yourself and forgive others. + May you experience and share the gift of unconditional love. + May you see light, wherever the illusion of darkness appears. + +--- + +5. Gazorator + +MIT License + +Copyright (c) 2018 Martin Björkström + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +6. ASP.NET Core The MIT License (MIT) diff --git a/README.md b/README.md index a4390da25..a474f0521 100644 --- a/README.md +++ b/README.md @@ -115,13 +115,22 @@ For questions and to discuss ideas & feature requests, use the [GitHub discussio | Cake Scripting Addin | Cake Frosting Addin | Description | |:--:|-|-| | [Cake.Issues](https://www.nuget.org/packages/Cake.Issues) | [Cake.Issues](https://www.nuget.org/packages/Cake.Issues) | Addin providing the aliases for creating and reading of issues. | +| [Cake.Issues.MsBuild](https://www.nuget.org/packages/Cake.Issues.MsBuild) | [Cake.Frosting.Issues.MsBuild](https://www.nuget.org/packages/Cake.Frosting.Issues.MsBuild) | Issue provider for reading MsBuild errors and warnings. | +| [Cake.Issues.DocFx](https://www.nuget.org/packages/Cake.Issues.DocFx) | [Cake.Frosting.Issues.DocFx](https://www.nuget.org/packages/Cake.Frosting.Issues.DocFx) | Issue provider for reading DocFx warnings. | +| [Cake.Issues.EsLint](https://www.nuget.org/packages/Cake.Issues.EsLint) | [Cake.Frosting.Issues.EsLint](https://www.nuget.org/packages/Cake.Frosting.Issues.EsLint) | Issue provider for reading ESLint issues. | +| [Cake.Issues.GitRepository](https://www.nuget.org/packages/Cake.Issues.GitRepository) | [Cake.Frosting.Issues.GitRepository](https://www.nuget.org/packages/Cake.Frosting.Issues.GitRepository) | Issue provider for analyzing Git repositories. | +| [Cake.Issues.InspectCode](https://www.nuget.org/packages/Cake.Issues.InspectCode) | [Cake.Frosting.Issues.InspectCode](https://www.nuget.org/packages/Cake.Frosting.Issues.InspectCode) | Issue provider for reading JetBrains Inspect Code issues. | +| [Cake.Issues.Markdownlint](https://www.nuget.org/packages/Cake.Issues.Markdownlint) | [Cake.Frosting.Issues.Markdownlint](https://www.nuget.org/packages/Cake.Frosting.Issues.Markdownlint) | Issue provider for reading issues from markdownlint. | +| [Cake.Issues.Sarif](https://www.nuget.org/packages/Cake.Issues.Sarif) | [Cake.Frosting.Issues.Sarif](https://www.nuget.org/packages/Cake.Frosting.Issues.Sarif) | Issue provider for reading SARIF reports. | +| [Cake.Issues.Terraform](https://www.nuget.org/packages/Cake.Issues.Terraform) | [Cake.Frosting.Issues.Terraform](https://www.nuget.org/packages/Cake.Frosting.Issues.Terraform) | Issue provider for reading Terraform validation output. | | [Cake.Issues.PullRequests](https://www.nuget.org/packages/Cake.Issues.PullRequests) | [Cake.Frosting.Issues.PullRequests](https://www.nuget.org/packages/Cake.Frosting.Issues.PullRequests) | Addin providing the aliases for writing issues to pull requests and build servers. | +| [Cake.Issues.PullRequests.AppVeyor](https://www.nuget.org/packages/Cake.Issues.PullRequests.AppVeyor) | [Cake.Frosting.Issues.PullRequests.AppVeyor](https://www.nuget.org/packages/Cake.Frosting.Issues.PullRequests.AppVeyor) | Integration with AppVeyor builds. | +| [Cake.Issues.PullRequests.AzureDevOps](https://www.nuget.org/packages/Cake.Issues.PullRequests.AzureDevOps) | [Cake.Frosting.Issues.PullRequests.AzureDevOps](https://www.nuget.org/packages/Cake.Frosting.Issues.PullRequests.AzureDevOps) | Integration with Azure DevOps pull requests. | +| [Cake.Issues.PullRequests.GitHubActions](https://www.nuget.org/packages/Cake.Issues.PullRequests.GitHubActions) | [Cake.Frosting.Issues.PullRequests.GitHubActions](https://www.nuget.org/packages/Cake.Frosting.Issues.PullRequests.GitHubActions) | Integration with GitHub Actions. | | [Cake.Issues.Reporting](https://www.nuget.org/packages/Cake.Issues.Reporting) | [Cake.Frosting.Issues.Reporting](https://www.nuget.org/packages/Cake.Frosting.Issues.Reporting) | Addin providing the aliases for creating reports. | -| [Cake.Issues.MsBuild](https://www.nuget.org/packages/Cake.Issues.MsBuild) | [Cake.Frosting.Issues.MsBuild](https://www.nuget.org/packages/Cake.Frosting.Issues.MsBuild) | Issue provider for reading MsBuild errors and warnings. | -| [Cake.Issues.DocFx](https://www.nuget.org/packages/Cake.Issues.DocFx) | [Cake.Issues.DocFx](https://www.nuget.org/packages/Cake.Issues.DocFx) | Issue provider for reading DocFx warnings. | -| [Cake.Issues.EsLint](https://www.nuget.org/packages/Cake.Issues.EsLint) | [Cake.Issues.EsLint](https://www.nuget.org/packages/Cake.Issues.EsLint) | Issue provider for reading ESLint issues. | -| [Cake.Issues.InspectCode](https://www.nuget.org/packages/Cake.Issues.InspectCode) | [Cake.Issues.InspectCode](https://www.nuget.org/packages/Cake.Issues.InspectCode) | Issue provider for reading JetBrains Inspect Code issues. | -| [Cake.Issues.Markdownlint](https://www.nuget.org/packages/Cake.Issues.Markdownlint) | [Cake.Issues.Markdownlint](https://www.nuget.org/packages/Cake.Issues.Markdownlint) | Issue provider for reading issues from markdownlint. | +| [Cake.Issues.Reporting.Console](https://www.nuget.org/packages/Cake.Issues.Reporting.Console) | [Cake.Frosting.Issues.Reporting.Console](https://www.nuget.org/packages/Cake.Frosting.Issues.Reporting.Console) | Support for reporting issues to the console. | +| [Cake.Issues.Reporting.Generic](https://www.nuget.org/packages/Cake.Issues.Reporting.Generic) | [Cake.Frosting.Issues.Reporting.Generic](https://www.nuget.org/packages/Cake.Frosting.Issues.Reporting.Generic) | Support for creating reports in any text based format (HTML, Markdown, ...). | +| [Cake.Issues.Reporting.Sarif](https://www.nuget.org/packages/Cake.Issues.Reporting.Sarif) | [Cake.Frosting.Issues.Reporting.Sarif](https://www.nuget.org/packages/Cake.Frosting.Issues.Reporting.Sarif) | Support for creating reports in SARIF format. | ## API diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 793e0a2b1..243e45f49 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -34,6 +34,38 @@ stages: displayName: 'Publish NuGet package as build artifact' condition: eq( variables['System.JobName'], 'Windows' ) +- stage: IntegrationTestsGitRepositoryStage + displayName: Integration Tests Cake.Issues.GitRepository + dependsOn: BuildStage + jobs: + - job: TestGitRepositoryScriptingJob + displayName: Test Cake Scripting + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.GitRepository/script-runner + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/BuildArtifacts/TestResults/Integration + artifact: Integration Tests Cake.Issues.GitRepository Cake Scripting $(System.JobName) + displayName: 'Publish generated reports as build artifact' + - stage: IntegrationTestsMarkdownlintStage displayName: Integration Tests Cake.Issues.Markdownlint dependsOn: BuildStage @@ -57,28 +89,243 @@ stages: pool: vmImage: $(imageName) steps: - - task: UseDotNet@2 - inputs: - version: '6.x' - displayName: 'Install .NET 6' - - task: NodeTool@0 - inputs: - versionSpec: '18.x' - displayName: 'Install NodeJs 18.x' - - bash: | - npm install -g markdownlint-cli - displayName: 'Install required tools' - - download: current - artifact: NuGet Package - displayName: 'Download build artifact' - - task: CopyFiles@2 - inputs: - sourceFolder: $(Pipeline.Workspace)/NuGet Package - targetFolder: $(Build.SourcesDirectory)/BuildArtifacts/Packages/NuGet - displayName: 'Copy build artifact for test run' + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml - powershell: ./build.ps1 --verbosity=diagnostic workingDirectory: ./tests/Cake.Issues.Markdownlint displayName: 'Run integration tests' - publish: $(Build.SourcesDirectory)/tests/Cake.Issues.Markdownlint/output/report.html - artifact: Integration Tests $(System.JobName) + artifact: Integration Tests Cake.Issues.Markdownlint $(System.JobName) + displayName: 'Publish generated reports as build artifact' + +- stage: IntegrationTestsReportingConsoleStage + displayName: Integration Tests Cake.Issues.Reporting.Console + dependsOn: BuildStage + jobs: + - job: TestReportingConsoleScriptingJob + displayName: Test Cake Scripting + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Console/script-runner + displayName: 'Run integration tests' + - job: TestReportingConsoleFrostingNet6Job + displayName: Test Cake Frosting .NET 6 + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Console/frosting/net6.0 + displayName: 'Run integration tests' + +- stage: IntegrationTestsReportingGenericStage + displayName: Integration Tests Cake.Issues.Reporting.Generic + dependsOn: BuildStage + jobs: + - job: TestReportingGenericScriptingJob + displayName: Test Cake Scripting + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Generic/script-runner + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/docs/input/docs/report-formats/generic/templates + artifact: Integration Tests Cake.Issues.Reporting.Generic Cake Scripting $(System.JobName) + displayName: 'Publish generated reports as build artifact' + - job: TestReportingGenericFrostingNet6Job + displayName: Test Cake Frosting .NET 6 + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Generic/frosting + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/docs/input/docs/report-formats/generic/templates + artifact: Integration Tests Cake.Issues.Reporting.Generic Cake Frosting .NET 6 $(System.JobName) + displayName: 'Publish generated reports as build artifact' + +- stage: IntegrationTestsReportingSarifStage + displayName: Integration Tests Cake.Issues.Reporting.Sarif + dependsOn: BuildStage + jobs: + - job: TestReportingSarifScriptingJob + displayName: Test Cake Scripting + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Sarif/script-runner + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/tests/Cake.Issues.Reporting.Sarif/script-runner/output + artifact: Integration Tests Cake.Issues.Reporting.Sarif Cake Scripting $(System.JobName) + displayName: 'Publish generated reports as build artifact' + - job: TestReportingSarifFrostingNet6Job + displayName: Test Cake Frosting .NET 6 + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net6.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Sarif/frosting/net6 + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/tests/Cake.Issues.Reporting.Sarif/frosting/output + artifact: Integration Tests Cake.Issues.Reporting.Sarif Cake Frosting .NET 6 $(System.JobName) + displayName: 'Publish generated reports as build artifact' + - job: TestReportingSarifFrostingNet7Job + displayName: Test Cake Frosting .NET 7 + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net7.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Sarif/frosting/net7 + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/tests/Cake.Issues.Reporting.Sarif/frosting/output + artifact: Integration Tests Cake.Issues.Reporting.Sarif Cake Frosting .NET 7 $(System.JobName) + displayName: 'Publish generated reports as build artifact' + - job: TestReportingSarifFrostingNet8Job + displayName: Test Cake Frosting .NET 8 + strategy: + matrix: + Windows_Server_2019: + imageName: 'windows-2019' + Windows_Server_2022: + imageName: 'windows-2022' + macOS_11: + imageName: 'macOS-11' + macOS_13: + imageName: 'macOS-13' + Ubuntu_20_04: + imageName: 'ubuntu-20.04' + Ubuntu_22_04: + imageName: 'ubuntu-22.04' + pool: + vmImage: $(imageName) + steps: + - template: .azuredevops/pipelines/templates/steps/install-net8.yml + - template: .azuredevops/pipelines/templates/steps/install-markdownlint.yml + - template: .azuredevops/pipelines/templates/steps/provide-nuget-packages.yml + - powershell: ./build.ps1 --verbosity=diagnostic + workingDirectory: ./tests/Cake.Issues.Reporting.Sarif/frosting/net8 + displayName: 'Run integration tests' + - publish: $(Build.SourcesDirectory)/tests/Cake.Issues.Reporting.Sarif/frosting/output + artifact: Integration Tests Cake.Issues.Reporting.Sarif Cake Frosting .NET 8 $(System.JobName) displayName: 'Publish generated reports as build artifact' diff --git a/docs/input/docs/issue-providers/gitrepository/examples.md b/docs/input/docs/issue-providers/gitrepository/examples.md new file mode 100644 index 000000000..28c116f38 --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/examples.md @@ -0,0 +1,54 @@ +--- +Order: 30 +Title: Examples +Description: Examples for using the Cake.Issues.GitRepository addin. +--- +The following example prints the number of binary files which are not tracked by [Git Large File Storage] in a repository. + +:::{.alert .alert-warning} +Checking binary files requires Git and [Git Large File Storage] available on the local machine. +::: + +To analyze Git repositories you need to import the core addin and the Git repository support: + +```csharp +#addin "Cake.Issues" +#addin "Cake.Issues.GitRepository" +``` + +:::{.alert .alert-warning} +Please note that you always should pin addins to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the addins. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +We need some global variables: + +```csharp +var repoRootPath = @"c:\repo"; +``` + +The following task will analyze the repository: + +```csharp +Task("Analyze-Repo") +.Does(() => +{ + // Read Issues. + var settings = + new GitRepositoryIssuesSettings + { + CheckBinaryFilesTrackedByLfs = true + }; + + var issues = + ReadIssues( + GitRepositoryIssues(settings), + repoRootPath); + + Information("{0} issues are found.", issues.Count()); +}); +``` + +[Git Large File Storage]: https://git-lfs.github.com/ \ No newline at end of file diff --git a/docs/input/docs/issue-providers/gitrepository/features.md b/docs/input/docs/issue-providers/gitrepository/features.md new file mode 100644 index 000000000..55dbdfcc4 --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/features.md @@ -0,0 +1,39 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.GitRepository addin. +--- +The [Cake.Issues.GitRepository addin] provides the following features. + +# Basic features + +* Checks path length of files. See [FilePathTooLong] for details. +* Checks if binary files are tracked by Git LFS. See [BinaryFileNotTrackedByLfs] for details. + +# Supported IIssue properties + +| | Property | Remarks | +|--------------------------------------------------------------------|-----------------------------------|---------------------------------| +| | `IIssue.ProviderType` | | +| | `IIssue.ProviderName` | | +| | `IIssue.Run` | Can be set while reading issues | +| | `IIssue.Identifier` | Set to `IIssue.MessageText` | +| | `IIssue.ProjectName` | | +| | `IIssue.ProjectFileRelativePath` | | +| | `IIssue.AffectedFileRelativePath` | | +| | `IIssue.Line` | | +| | `IIssue.EndLine` | | +| | `IIssue.Column` | | +| | `IIssue.EndColumn` | | +| | `IIssue.FileLink` | Can be set while reading issues | +| | `IIssue.MessageText` | | +| | `IIssue.MessageHtml` | | +| | `IIssue.MessageMarkdown` | | +| | `IIssue.Priority` | | +| | `IIssue.PriorityName` | | +| | `IIssue.Rule` | | +| | `IIssue.RuleUrl` | | + +[Cake.Issues.GitRepository addin]: https://www.nuget.org/packages/Cake.Issues.GitRepository +[FilePathTooLong]: rules/FilePathTooLong +[BinaryFileNotTrackedByLfs]: rules/BinaryFileNotTrackedByLfs diff --git a/docs/input/docs/issue-providers/gitrepository/index.cshtml b/docs/input/docs/issue-providers/gitrepository/index.cshtml new file mode 100644 index 000000000..35d944fbd --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/index.cshtml @@ -0,0 +1,11 @@ +--- +Title: Git Repository +Description: Issue provider which allows you to analyzing Git repositories and create issues resulting from it. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +

+ Support for analyzing Git repositories is implemented in the Cake.Issues.GitRepository addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/issue-providers/gitrepository/requirements.md b/docs/input/docs/issue-providers/gitrepository/requirements.md new file mode 100644 index 000000000..e491db400 --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.GitRepository addin. +--- +The requirements for using the [Cake.Issues.GitRepository addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.GitRepository addin]: https://www.nuget.org/packages/Cake.Issues.GitRepository +[release notes]: release-notes diff --git a/docs/input/docs/issue-providers/gitrepository/rules/BinaryFileNotTrackedByLfs.md b/docs/input/docs/issue-providers/gitrepository/rules/BinaryFileNotTrackedByLfs.md new file mode 100644 index 000000000..ccf4197bb --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/rules/BinaryFileNotTrackedByLfs.md @@ -0,0 +1,33 @@ +--- +Title: BinaryFileNotTrackedByLfs +Description: A binary file is not tracked by Git LFS. +--- + + + + + +## Cause + +A binary file in the repository is not tracked by [Git Large File System]. + +## Rule description + +By its nature Git repositories cannot handle binary files well and will keep a full copy of that file in the repository every time a change to that file is committed. +Considering that you always clone the full history of a repository, and not only the latest version, using binary files in a repository considerably slow downs the operation. +[Git Large File System] replaces large files with small text pointers inside the Git repository, while storing the file contents on a remote server. + +:::{.alert .alert-info} +The rule assumes that all files, which are not text files are binary files. +This also includes for example empty files. +::: + +## How to fix violations + +Track the file with [Git Large File System]. + +[Git Large File System]: https://git-lfs.github.com/ diff --git a/docs/input/docs/issue-providers/gitrepository/rules/FilePathTooLong.md b/docs/input/docs/issue-providers/gitrepository/rules/FilePathTooLong.md new file mode 100644 index 000000000..e3eb20e67 --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/rules/FilePathTooLong.md @@ -0,0 +1,25 @@ +--- +Title: FilePathTooLong +Description: The path of a file is too long. +--- + + + + + +## Cause + +The path of a file in the repository is too long. + +## Rule description + +Some operating systems and applications have a limitation of maximum path length which they can handle. +To guarantee proper building this length should not be exceeded. + +## How to fix violations + +Rename the name of the file or shorten the path name. diff --git a/docs/input/docs/issue-providers/gitrepository/rules/index.cshtml b/docs/input/docs/issue-providers/gitrepository/rules/index.cshtml new file mode 100644 index 000000000..31e0d52d1 --- /dev/null +++ b/docs/input/docs/issue-providers/gitrepository/rules/index.cshtml @@ -0,0 +1,7 @@ +--- +Title: Rules +Description: Rules of the Cake.Issues.GitRepository provider. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/issue-providers/terraform/features.md b/docs/input/docs/issue-providers/terraform/features.md new file mode 100644 index 000000000..dbb414f25 --- /dev/null +++ b/docs/input/docs/issue-providers/terraform/features.md @@ -0,0 +1,37 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.Terraform addin. +--- +The [Cake.Issues.Terraform addin] provides the following features: + +# Basic features + +* Reads warnings from [Terraform validate command]. + +# Supported IIssue properties + +| | Property | Remarks | +|--------------------------------------------------------------------|-----------------------------------|----------------------------------| +| | `IIssue.ProviderType` | | +| | `IIssue.ProviderName` | | +| | `IIssue.Run` | Can be set while reading issues | +| | `IIssue.Identifier` | Set to `IIssue.MessageText` | +| | `IIssue.ProjectName` | | +| | `IIssue.ProjectFileRelativePath` | | +| | `IIssue.AffectedFileRelativePath` | | +| | `IIssue.Line` | | +| | `IIssue.EndLine` | | +| | `IIssue.Column` | | +| | `IIssue.EndColumn` | | +| | `IIssue.FileLink` | Can be set while reading issues | +| | `IIssue.MessageText` | | +| | `IIssue.MessageHtml` | | +| | `IIssue.MessageMarkdown` | | +| | `IIssue.Priority` | | +| | `IIssue.PriorityName` | | +| | `IIssue.Rule` | | +| | `IIssue.RuleUrl` | | + +[Terraform validate command]: https://www.terraform.io/docs/cli/commands/validate.html +[Cake.Issues.Terraform addin]: https://cakebuild.net/extensions/cake-issues-terraform/ diff --git a/docs/input/docs/issue-providers/terraform/index.cshtml b/docs/input/docs/issue-providers/terraform/index.cshtml new file mode 100644 index 000000000..184598ebb --- /dev/null +++ b/docs/input/docs/issue-providers/terraform/index.cshtml @@ -0,0 +1,12 @@ +--- +Title: Terraform +Description: Issue provider which allows you to read issues from Terraform validate command. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +

+ Support for reading issues reported by Terraform validate command + is implemented in the Cake.Issues.Terraform addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/issue-providers/terraform/requirements.md b/docs/input/docs/issue-providers/terraform/requirements.md new file mode 100644 index 000000000..4b7a408f3 --- /dev/null +++ b/docs/input/docs/issue-providers/terraform/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.Terraform addin. +--- +The requirements for using the [Cake.Issues.Terraform addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.Terraform addin]: https://cakebuild.net/extensions/cake-issues-terraform/ +[release notes]: release-notes diff --git a/docs/input/docs/pull-request-systems/appveyor/appveyor-messages.png b/docs/input/docs/pull-request-systems/appveyor/appveyor-messages.png new file mode 100644 index 000000000..1487681a3 Binary files /dev/null and b/docs/input/docs/pull-request-systems/appveyor/appveyor-messages.png differ diff --git a/docs/input/docs/pull-request-systems/appveyor/examples/github-pullrequest-integration.md b/docs/input/docs/pull-request-systems/appveyor/examples/github-pullrequest-integration.md new file mode 100644 index 000000000..2620901b5 --- /dev/null +++ b/docs/input/docs/pull-request-systems/appveyor/examples/github-pullrequest-integration.md @@ -0,0 +1,24 @@ +--- +Order: 20 +Title: GitHub pull request integration +Description: Example how to write AppVeyor message to GitHub pull requests. +--- +This example shows how to write AppVeyor messages created by Cake.Issues to GitHub pull requests. + +Issues reported as messages to AppVeyor builds can be written to a GitHub pull request using [GitHub Pull Request Notification] +in your `appveyor.yml` file. + +The following example will write a comment to the GitHub pull request containing all issues which were posted as message to the +AppVeyor build: + +```yml +notifications: +- provider: GitHubPullRequest + template: "{{#passed}}:white_check_mark:{{/passed}}{{#failed}}:x:{{/failed}} [Build {{&projectName}} {{buildVersion}} {{status}}]({{buildUrl}}) (commit {{commitUrl}} by @{{&commitAuthorUsername}})

Build messages:

" +``` + +The output will look similar to this: + +![GitHub pull request integration](github-pullrequest-integration.png "GitHub pull request integration") + +[GitHub Pull Request Notification]: https://www.appveyor.com/docs/notifications/#github-pull-request \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/appveyor/examples/github-pullrequest-integration.png b/docs/input/docs/pull-request-systems/appveyor/examples/github-pullrequest-integration.png new file mode 100644 index 000000000..770fb99a3 Binary files /dev/null and b/docs/input/docs/pull-request-systems/appveyor/examples/github-pullrequest-integration.png differ diff --git a/docs/input/docs/pull-request-systems/appveyor/examples/index.cshtml b/docs/input/docs/pull-request-systems/appveyor/examples/index.cshtml new file mode 100644 index 000000000..f0d5372ef --- /dev/null +++ b/docs/input/docs/pull-request-systems/appveyor/examples/index.cshtml @@ -0,0 +1,12 @@ +--- +Title: Examples +Description: Examples for using the Cake.Issues.PullRequests.AppVeyor addin. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +
+There's a demo repository +available which you can fork and to which you can create pull requests to test the integration functionality. +
+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/appveyor/examples/write-messages.md b/docs/input/docs/pull-request-systems/appveyor/examples/write-messages.md new file mode 100644 index 000000000..10cccdfb4 --- /dev/null +++ b/docs/input/docs/pull-request-systems/appveyor/examples/write-messages.md @@ -0,0 +1,46 @@ +--- +Order: 10 +Title: Writing message to AppVeyor +Description: Example how to write issues as messages to an AppVeyor build. +--- +This example shows how to report issues as messages to an AppVeyor build. + +To report issues as messages to an AppVeyor build you need to import the core addin, +the core pull request addin, the AppVeyor support and one or more issue providers, +in this example for JetBrains InspectCode: + +```csharp +#addin "Cake.Issues" +#addin "Cake.Issues.InspectCode" +#addin "Cake.Issues.PullRequests" +#addin "Cake.Issues.PullRequests.AppVeyor" +``` + +:::{.alert .alert-warning} +Please note that you always should pin addins to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the addins. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +In the following task we'll first determine the remote repository URL and +source branch of the pull request and with this information call the [AppVeyorBuilds] alias: + +```csharp +Task("ReportIssuesToAppVeyor").Does(() => +{ + var repoRootFolder = MakeAbsolute(Directory("./")); + + ReportIssuesToPullRequest( + InspectCodeIssuesFromFilePath( + @"C:\build\inspectcode.log"), + AppVeyorBuilds(), + repoRootFolder); +}); +``` + +The output will look similar to this: + +![AppVeyor messages](../appveyor-messages.png "AppVeyor messages") + +[AppVeyorBuilds]: ../../../../api/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildsAliases/ \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/appveyor/features.md b/docs/input/docs/pull-request-systems/appveyor/features.md new file mode 100644 index 000000000..68211906f --- /dev/null +++ b/docs/input/docs/pull-request-systems/appveyor/features.md @@ -0,0 +1,32 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.PullRequests.AppVeyor addin. +--- +The [Cake.Issues.PullRequests.AppVeyor addin] reports issues as messages to AppVeyor builds. + +![AppVeyor messages](appveyor-messages.png "AppVeyor messages") + +:::{.alert .alert-info} +There's a [demo repository] available which you can fork and to which you can create pull requests to test the integration functionality. +::: + +# Basic features + +* Reports issues as messages to AppVeyor builds. +* Messages can be written as comment to GitHub pull requests. + See [GitHub pull request integration] for an example. + +# Supported capabilities + +The [Cake.Issues.PullRequests.AppVeyor addin] doesn't support any additional capabilities. + +| | Capability | Remarks | +|--------------------------------------------------------------------|--------------------------------|--------------------------------| +| | Checking commit ID | | +| | Discussion threads | | +| | Filtering by modified files | | + +[demo repository]: https://github.com/pascalberger/Cake.Issues-Demo +[Cake.Issues.PullRequests.AppVeyor addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.AppVeyor +[GitHub pull request integration]: ./examples/github-pullrequest-integration diff --git a/docs/input/docs/pull-request-systems/appveyor/index.cshtml b/docs/input/docs/pull-request-systems/appveyor/index.cshtml new file mode 100644 index 000000000..f704df063 --- /dev/null +++ b/docs/input/docs/pull-request-systems/appveyor/index.cshtml @@ -0,0 +1,10 @@ +--- +Title: AppVeyor +Description: Support for AppVeyor. +--- +

+ Support for AppVeyor is implemented in the + Cake.Issues.PullRequests.AppVeyor addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/appveyor/requirements.md b/docs/input/docs/pull-request-systems/appveyor/requirements.md new file mode 100644 index 000000000..446b03b69 --- /dev/null +++ b/docs/input/docs/pull-request-systems/appveyor/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.PullRequests.AppVeyor addin. +--- +The requirements for using the [Cake.Issues.PullRequests.AppVeyor addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.PullRequests.AppVeyor addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.AppVeyor +[release notes]: release-notes \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/azure-devops/cake.issues.pullrequests.azuredevops.png b/docs/input/docs/pull-request-systems/azure-devops/cake.issues.pullrequests.azuredevops.png new file mode 100644 index 000000000..af5eda3c0 Binary files /dev/null and b/docs/input/docs/pull-request-systems/azure-devops/cake.issues.pullrequests.azuredevops.png differ diff --git a/docs/input/docs/pull-request-systems/azure-devops/examples/azure-pipelines.md b/docs/input/docs/pull-request-systems/azure-devops/examples/azure-pipelines.md new file mode 100644 index 000000000..6078ba5ac --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/examples/azure-pipelines.md @@ -0,0 +1,83 @@ +--- +Order: 30 +Title: Using with Azure Pipelines +Description: Example how to use the Cake.Issues.PullRequests.AzureDevOps addin from an Azure Pipelines build. +--- +This example shows how to write issues as comments to an Azure DevOps pull request from an Azure Pipelines build. + +To write issues as comments to Azure DevOps pull requests you need to import the core addin, +the core pull request addin, the Azure DevOps support including the Cake.AzureDevOps addin, and one or more issue providers, +in this example for JetBrains InspectCode: + +```csharp +#addin "Cake.Issues" +#addin "Cake.Issues.InspectCode" +#addin "Cake.Issues.PullRequests" +#addin "Cake.Issues.PullRequests.AzureDevOps" +#addin "Cake.AzureDevOps" +``` + +:::{.alert .alert-warning} +Please note that you always should pin addins to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the addins. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +In the following task we'll first determine if the build is running on Azure DevOps and for a pull request, +then read the remote repository URL and pull request id from environment variables set by the Azure Pipelines build +and finally call the [AzureDevOpsPullRequests] alias using the OAuth token provided by the Azure Pipeline build. + +:::{.alert .alert-info} +Please note that you'll need to setup your Azure Pipelines build to allow scripts to +access the OAuth token and need to setup proper permissions. + +See [OAuth authentication from Azure Pipelines] for details. +::: + +```csharp +Task("ReportIssuesToPullRequest").Does(() => +{ + var isRunningOnAzureDevOps = + !string.IsNullOrWhiteSpace(context.EnvironmentVariable("TF_BUILD")) && + !string.IsNullOrWhiteSpace(context.EnvironmentVariable("SYSTEM_COLLECTIONURI")) && + ( + new Uri(context.EnvironmentVariable("SYSTEM_COLLECTIONURI")).Host == "dev.azure.com" || + new Uri(context.EnvironmentVariable("SYSTEM_COLLECTIONURI")).Host.EndsWith("visualstudio.com") + ); + + var isPullRequestBuild = + !string.IsNullOrWhiteSpace(context.EnvironmentVariable("SYSTEM_PULLREQUEST_PULLREQUESTID")); + + if (isRunningOnAzureDevOps) + { + var repositoryUrl = new Uri(context.EnvironmentVariable("BUILD_REPOSITORY_URI")); + + if (isPullRequestBuild) + { + var pullRequestIdVariable = context.EnvironmentVariable("SYSTEM_PULLREQUEST_PULLREQUESTID"); + if (!Int32.TryParse(pullRequestIdVariable, out var pullRequestId)) + { + throw new Exception($"Invalid pull request ID: {pullRequestIdVariable}"); + } + else + { + var repoRootFolder = MakeAbsolute(Directory("./")); + + ReportIssuesToPullRequest( + InspectCodeIssuesFromFilePath( + @"C:\build\inspectcode.log"), + AzureDevOpsPullRequests( + repositoryUrl, + pullRequestId, + AzureDevOpsAuthenticationOAuth(EnvironmentVariable("SYSTEM_ACCESSTOKEN"))), + repoRootFolder); + } + } + } +}); +``` + +[AzureDevOpsPullRequests]: ../../../../api/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases/64912B0A +[Allow scripts to access the OAuth token]: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/options#allow-scripts-to-access-the-oauth-token +[OAuth authentication from Azure Pipelines]: ../setup#oauth-authentication-from-azure-pipelines diff --git a/docs/input/docs/pull-request-systems/azure-devops/examples/index.cshtml b/docs/input/docs/pull-request-systems/azure-devops/examples/index.cshtml new file mode 100644 index 000000000..17e2702db --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/examples/index.cshtml @@ -0,0 +1,12 @@ +--- +Title: Examples +Description: Examples for using the Cake.Issues.PullRequests.AzureDevOps addin. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +
+There's a demo repository +available which you can fork and to which you can create pull requests to test the integration functionality. +
+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/azure-devops/examples/pullrequest-id.md b/docs/input/docs/pull-request-systems/azure-devops/examples/pullrequest-id.md new file mode 100644 index 000000000..843390dfc --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/examples/pullrequest-id.md @@ -0,0 +1,56 @@ +--- +Order: 10 +Title: Using with pull request id +Description: Example how to use the Cake.Issues.PullRequests.AzureDevOps addin with pull request id. +--- +This example shows how to write issues as comments to an Azure DevOps pull request while using pull request id. + +To determine the remote repository URL you need the [Cake.Git] addin: + +```csharp +#addin "Cake.Git" +``` + +To write issues as comments to Azure DevOps pull requests you need to import the core addin, +the core pull request addin, the Azure DevOps support including the Cake.AzureDevOps addin, and one or more issue providers, +in this example for JetBrains InspectCode: + +```csharp +#addin "Cake.Issues" +#addin "Cake.Issues.InspectCode" +#addin "Cake.Issues.PullRequests" +#addin "Cake.Issues.PullRequests.AzureDevOps" +#addin "Cake.AzureDevOps" +``` + +:::{.alert .alert-warning} +Please note that you always should pin addins to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the addins. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +In the following task we'll first determine the remote repository URL and +with this information call the [AzureDevOpsPullRequests] alias, +which will authenticate through NTLM to an on-premise Azure DevOps Server instance: + +```csharp +Task("ReportIssuesToPullRequest").Does(() => +{ + var repoRootFolder = MakeAbsolute(Directory("./")); + var repoRemoteUrl = new Uri(currentBranch.Remotes.Single(x => x.Name == "origin").Url); + var pullRequestId = 123; + + ReportIssuesToPullRequest( + InspectCodeIssuesFromFilePath( + @"C:\build\inspectcode.log"), + AzureDevOpsPullRequests( + repoRemoteUrl, + pullRequestId, + AzureDevOpsAuthenticationNtlm()), + repoRootFolder); +}); +``` + +[AzureDevOpsPullRequests]: ../../../../api/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases/64912B0A +[Cake.Git]: https://www.nuget.org/packages/Cake.Git/ diff --git a/docs/input/docs/pull-request-systems/azure-devops/examples/repository-information.md b/docs/input/docs/pull-request-systems/azure-devops/examples/repository-information.md new file mode 100644 index 000000000..804ef7cfd --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/examples/repository-information.md @@ -0,0 +1,57 @@ +--- +Order: 20 +Title: Using with repository remote url and source branch name +Description: Example how to use the Cake.Issues.PullRequests.AzureDevOps addin with repository remote url and source branch name. +--- +This example shows how to write issues as comments to an Azure DevOps pull request while using repository information. + +To determine the remote repository URL and source branch of the pull request you need the [Cake.Git] addin: + +```csharp +#addin "Cake.Git" +``` + +To write issues as comments to Azure DevOps pull requests you need to import the core addin, +the core pull request addin, the Azure DevOps support including the Cake.AzureDevOps addin, and one or more issue providers, +in this example for JetBrains InspectCode: + +```csharp +#addin "Cake.Issues" +#addin "Cake.Issues.InspectCode" +#addin "Cake.Issues.PullRequests" +#addin "Cake.Issues.PullRequests.AzureDevOps" +#addin "Cake.AzureDevOps" +``` + +:::{.alert .alert-warning} +Please note that you always should pin addins to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the addins. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +In the following task we'll first determine the remote repository URL and +source branch of the pull request and with this information call the [AzureDevOpsPullRequests] alias, +which will authenticate through NTLM to an on-premise Azure DevOps Server instance: + +```csharp +Task("ReportIssuesToPullRequest").Does(() => +{ + var repoRootFolder = MakeAbsolute(Directory("./")); + var currentBranch = GitBranchCurrent(repoRootFolder); + var repoRemoteUrl = new Uri(currentBranch.Remotes.Single(x => x.Name == "origin").Url); + var sourceBranchName = currentBranch.CanonicalName; + + ReportIssuesToPullRequest( + InspectCodeIssuesFromFilePath( + @"C:\build\inspectcode.log"), + AzureDevOpsPullRequests( + repoRemoteUrl, + sourceBranchName, + AzureDevOpsAuthenticationNtlm()), + repoRootFolder); +}); +``` + +[AzureDevOpsPullRequests]: ../../../../api/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases/8D75BECA +[Cake.Git]: https://www.nuget.org/packages/Cake.Git/ diff --git a/docs/input/docs/pull-request-systems/azure-devops/features.md b/docs/input/docs/pull-request-systems/azure-devops/features.md new file mode 100644 index 000000000..b3b4bc228 --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/features.md @@ -0,0 +1,48 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.PullRequests.AzureDevOps addin. +--- +The [Cake.Issues.PullRequests.AzureDevOps addin] provides the following features. + +:::{.alert .alert-info} +There's a [demo repository] available which you can fork and to which you can create pull requests to test the integration functionality. +::: + +# Basic features + +* Writes issues as comments to [Azure DevOps] pull requests. +* Identification of pull requests through source branch or pull request ID. +* Comments written by the addin will be rendered with a specific icon corresponding to the state of the issue. +* Adds rule number and, if provided by the issue provider, link to the rule description to the comment. +* Support for issues messages formatted in Markdown format. + +# Supported capabilities + +The [Cake.Issues.PullRequests.AzureDevOps addin] supports all [Core features]. + +| | Capability | Remarks | +|--------------------------------------------------------------------|--------------------------------|--------------------------------| +| | Checking commit ID | | +| | Discussion threads | | +| | Filtering by modified files | | + +# Supported authentication methods + +| Azure DevOps Server | Azure DevOps Service | Authentication method | +|--------------------------------------------------------------------|--------------------------------------------------------------------|--------------------------------| +| | | NTLM | +| | | Basic authentication | +| | | Personal access token | +| | | OAuth | +| | | Azure Active Directory | + +For detailed instructions how to connect using the different methods see [Setup instructions]. + +![Cake.Issues.PullRequests.AzureDevOps](cake.issues.pullrequests.azuredevops.png "Cake.Issues.PullRequests.AzureDevOps") + +[demo repository]: https://dev.azure.com/pberger/Cake.Issues-Demo +[Cake.Issues.PullRequests.AzureDevOps addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.AzureDevOps +[Azure DevOps]: https://azure.microsoft.com/en-us/services/devops/ +[Core features]: ../../overview/features#supported-core-functionality +[Setup instructions]: setup diff --git a/docs/input/docs/pull-request-systems/azure-devops/index.cshtml b/docs/input/docs/pull-request-systems/azure-devops/index.cshtml new file mode 100644 index 000000000..fbf68afda --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/index.cshtml @@ -0,0 +1,10 @@ +--- +Title: Azure DevOps +Description: Support for Azure DevOps. +--- +

+ Support for Azure DevOps is implemented in the + Cake.Issues.PullRequests.AzureDevOps addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/azure-devops/requirements.md b/docs/input/docs/pull-request-systems/azure-devops/requirements.md new file mode 100644 index 000000000..9c245110d --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.PullRequests.AzureDevOps addin. +--- +The requirements for using the [Cake.Issues.PullRequests.AzureDevOps addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.PullRequests.AzureDevOps addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.AzureDevOps +[release notes]: release-notes diff --git a/docs/input/docs/pull-request-systems/azure-devops/setup.md b/docs/input/docs/pull-request-systems/azure-devops/setup.md new file mode 100644 index 000000000..ac9f128bb --- /dev/null +++ b/docs/input/docs/pull-request-systems/azure-devops/setup.md @@ -0,0 +1,78 @@ +--- +Order: 30 +Title: Setup +Description: Instructions how to setup the Cake.Issues.PullRequests.AzureDevOps addin. +--- +This page describes the different ways how the [Cake.Issues.PullRequests.AzureDevOps addin] can be setup. + +# NTLM authentication + +:::{.alert .alert-info} +NTLM authentication is only available for on-premise Azure DevOps Server. +::: + +To authenticate with NTLM you can use the [AzureDevOpsAuthenticationNtlm] alias from the [Cake.AzureDevOps addin]. + +The user needs to have `Contribute to pull requests` permission for the specific repository to +allow [Cake.Issues.PullRequests.AzureDevOps addin] to post issues as comments to pull requests. + +# Basic authentication + +:::{.alert .alert-info} +Basic authentication is only available for on-premise Azure DevOps Server. +::: + +To authenticate with basic authentication you can use the [AzureDevOpsAuthenticationBasic] alias from the [Cake.AzureDevOps addin] and +need to [Configure AzureDevOps Server to use Basic Authentication]. + +The user needs to have `Contribute to pull requests` permission for the specific repository to +allow [Cake.Issues.PullRequests.AzureDevOps addin] to post issues as comments to pull requests. + +# Personal access token + +To authenticate with an personal access token you can use the [AzureDevOpsAuthenticationPersonalAccessToken] alias from the [Cake.AzureDevOps addin]. + +If you want to use the [Cake.Issues.PullRequests.AzureDevOps addin] with an personal access token see +[Authenticate access with personal access tokens for Azure DevOps] for instructions how to create +a personal access token. + +The access token needs to have the scope `Code (read and write)` set and the user needs to have `Contribute to pull requests` +permission for the specific repository to allow [Cake.Issues.PullRequests.AzureDevOps addin] to post issues as comments to pull requests. + +# OAuth authentication from Azure Pipelines + +:::{.alert .alert-info} +OAuth authentication is only available for Azure DevOps Service. +::: + +If you want to use the [Cake.Issues.PullRequests.AzureDevOps addin] from an Azure Pipelines you can authenticate using the +OAuth token provided to the build. +For this you need to enable the [Allow scripts to access the OAuth token] option on the build definition. + +To authenticate you can use the [AzureDevOpsAuthenticationOAuth] alias from the [Cake.AzureDevOps addin]. + +The user under which the build runs, named ` Build Service ()` (e.g. `Cake.Issues-Demo Build Service (cake-contrib)`), +needs to have `Contribute to pull requests` permission for the specific repository to allow [Cake.Issues.PullRequests.AzureDevOps addin] +to post issues as comments to pull requests. + +# Azure Active Directory + +:::{.alert .alert-info} +OAuth authentication is only available for Azure DevOps Service. +::: + +To authenticate with Azure Active Directory you can use the [AzureDevOpsAuthenticationAzureActiveDirectory] alias from the [Cake.AzureDevOps addin]. + +The user needs to have `Contribute to pull requests` permission for the specific repository to +allow [Cake.Issues.PullRequests.AzureDevOps addin] to post issues as comments to pull requests. + +[Cake.Issues.PullRequests.AzureDevOps addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.AzureDevOps +[Cake.AzureDevOps addin]: https://www.nuget.org/packages/Cake.AzureDevOps +[Configure TFS to use Basic Authentication]: https://docs.microsoft.com/en-us/azure/devops/integrate/get-started/auth/tfs-basic-auth#configure-tfs-to-use-basic-authentication +[Authenticate access with personal access tokens for Azure DevOps]: https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate +[Allow scripts to access the OAuth token]: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/options#allow-scripts-to-access-the-oauth-token +[AzureDevOpsAuthenticationNtlm]: https://cakebuild.net/api/Cake.AzureDevOps/AzureDevOpsAliases/F2A040B7 +[AzureDevOpsAuthenticationBasic]: https://cakebuild.net/api/Cake.AzureDevOps/AzureDevOpsAliases/7CD679FF +[AzureDevOpsAuthenticationPersonalAccessToken]: https://cakebuild.net/api/Cake.AzureDevOps/AzureDevOpsAliases/F4DCC101 +[AzureDevOpsAuthenticationOAuth]: https://cakebuild.net/api/Cake.AzureDevOps/AzureDevOpsAliases/988E9C28 +[AzureDevOpsAuthenticationAzureActiveDirectory]: https://cakebuild.net/api/Cake.AzureDevOps/AzureDevOpsAliases/0B9F5DF6 diff --git a/docs/input/docs/pull-request-systems/github-actions/examples/index.cshtml b/docs/input/docs/pull-request-systems/github-actions/examples/index.cshtml new file mode 100644 index 000000000..f6edfee20 --- /dev/null +++ b/docs/input/docs/pull-request-systems/github-actions/examples/index.cshtml @@ -0,0 +1,7 @@ +--- +Title: Examples +Description: Examples for using the Cake.Issues.PullRequests.GitHubActions addin. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/github-actions/examples/write-annotations.md b/docs/input/docs/pull-request-systems/github-actions/examples/write-annotations.md new file mode 100644 index 000000000..719a51917 --- /dev/null +++ b/docs/input/docs/pull-request-systems/github-actions/examples/write-annotations.md @@ -0,0 +1,54 @@ +--- +Order: 10 +Title: Create annotations in GitHub Actions +Description: Example how to write issues as annotations to a GitHub Actions build. +--- +This example shows how to report issues as annotations to a GitHub Actions build. + +To report issues as annotations to a GitHub Actions build you need to import the core addin, +the core pull request addin, the GitHub Actions support and one or more issue providers, +in this example for JetBrains InspectCode: + +```csharp +#addin "Cake.Issues" +#addin "Cake.Issues.InspectCode" +#addin "Cake.Issues.PullRequests" +#addin "Cake.Issues.PullRequests.GitHubActions" +``` + +:::{.alert .alert-warning} +Please note that you always should pin addins to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the addins. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +In the following task we'll first determine the remote repository URL and +source branch of the pull request and with this information call the [GitHubActionsBuilds] alias: + +```csharp +Task("ReportIssuesToGitHubActions").Does(() => +{ + var repoRootFolder = MakeAbsolute(Directory("./")); + + ReportIssuesToPullRequest( + InspectCodeIssuesFromFilePath( + @"C:\build\inspectcode.log"), + GitHubActionsBuilds(), + repoRootFolder); +}); +``` + +The output will show up in the build log grouped by issue provider / run: + +![Log output](../githubactions-log-output.png "Log output") + +Additionally the issues show up as annotations: + +![Annotations](../githubactions-annotations.png "Annotations") + +Having issues available as annotations also means that they will be shown in pull requests on the related file / position: + +![Pull request integration](../githubactions-pullrequest-integration.png "Pull request integration") + +[GitHubActionsBuilds]: ../../../../api/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildsAliases/ diff --git a/docs/input/docs/pull-request-systems/github-actions/features.md b/docs/input/docs/pull-request-systems/github-actions/features.md new file mode 100644 index 000000000..91dea5e3c --- /dev/null +++ b/docs/input/docs/pull-request-systems/github-actions/features.md @@ -0,0 +1,25 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.PullRequests.GitHubActions addin. +--- +The [Cake.Issues.PullRequests.GitHubActions addin] creates annotations from issues when running on GitHub actions. + +![Pull request integration](githubactions-pullrequest-integration.png "Pull request integration") + +# Basic features + +* Reports issues as annotations to GitHub Actions builds. +* Group issues in log output by provider and run information. + +# Supported capabilities + +The [Cake.Issues.PullRequests.GitHubActions addin] doesn't support any additional capabilities. + +| | Capability | Remarks | +|--------------------------------------------------------------------|--------------------------------|--------------------------------| +| | Checking commit ID | | +| | Discussion threads | | +| | Filtering by modified files | | + +[Cake.Issues.PullRequests.GitHubActions addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.GitHubActions diff --git a/docs/input/docs/pull-request-systems/github-actions/githubactions-annotations.png b/docs/input/docs/pull-request-systems/github-actions/githubactions-annotations.png new file mode 100644 index 000000000..d9c8bb693 Binary files /dev/null and b/docs/input/docs/pull-request-systems/github-actions/githubactions-annotations.png differ diff --git a/docs/input/docs/pull-request-systems/github-actions/githubactions-log-output.png b/docs/input/docs/pull-request-systems/github-actions/githubactions-log-output.png new file mode 100644 index 000000000..779bc0b9b Binary files /dev/null and b/docs/input/docs/pull-request-systems/github-actions/githubactions-log-output.png differ diff --git a/docs/input/docs/pull-request-systems/github-actions/githubactions-pullrequest-integration.png b/docs/input/docs/pull-request-systems/github-actions/githubactions-pullrequest-integration.png new file mode 100644 index 000000000..def6f8cb0 Binary files /dev/null and b/docs/input/docs/pull-request-systems/github-actions/githubactions-pullrequest-integration.png differ diff --git a/docs/input/docs/pull-request-systems/github-actions/index.cshtml b/docs/input/docs/pull-request-systems/github-actions/index.cshtml new file mode 100644 index 000000000..aba361913 --- /dev/null +++ b/docs/input/docs/pull-request-systems/github-actions/index.cshtml @@ -0,0 +1,10 @@ +--- +Title: GitHub Actions +Description: Support for GitHub Actions. +--- +

+ Support for GitHub Actions is implemented in the + Cake.Issues.PullRequests.GitHubActions addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/pull-request-systems/github-actions/requirements.md b/docs/input/docs/pull-request-systems/github-actions/requirements.md new file mode 100644 index 000000000..e1e66947a --- /dev/null +++ b/docs/input/docs/pull-request-systems/github-actions/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.PullRequests.GitHubActions addin. +--- +The requirements for using the [Cake.Issues.PullRequests.GitHubActions addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.PullRequests.GitHubActions addin]: https://www.nuget.org/packages/Cake.Issues.PullRequests.GitHubActions +[release notes]: release-notes diff --git a/docs/input/docs/report-formats/console/examples.md b/docs/input/docs/report-formats/console/examples.md new file mode 100644 index 000000000..ea9f76c5d --- /dev/null +++ b/docs/input/docs/report-formats/console/examples.md @@ -0,0 +1,57 @@ +--- +Order: 30 +Title: Examples +Description: Examples for using the Cake.Issues.Reporting.Console addin. +--- +The following example will print issues logged as warnings by MsBuild to the console. + +:::{.alert .alert-warning} +Please note that you always should pin addins and tools to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the packages. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +```csharp +#tool "nuget:?package=MSBuild.Extension.Pack" +#addin "Cake.Issues" +#addin "Cake.Issues.MsBuild" +#addin "Cake.Issues.Reporting" +#addin "Cake.Issues.Reporting.Console" + +Task("Create-IssueReport").Does(() => +{ + var repoRootFolder = new DirectoryPath(@"c:\repo"); + + // Build MySolution.sln solution in the repository root folder and log issues + // using XmlFileLogger from MSBuild Extension Pack. + FilePath msBuildLogFile = @"c:\build\msbuild.log"; + var settings = new MsBuildSettings() + .WithLogger( + Context.Tools.Resolve("MSBuild.ExtensionPack.Loggers.dll").FullPath, + "XmlFileLogger", + string.Format( + "logfile=\"{0}\";verbosity=Detailed;encoding=UTF-8", + msBuildLogFile) + ); + MSBuild(repoRootFolder.CombineWithFilePath("MySolution.sln"), settings); + + // Write issues to console. + CreateIssueReport( + new List + { + MsBuildIssuesFromFilePath( + msBuildLogFile, + MsBuildXmlFileLoggerFormat) + }, + ConsoleIssueReportFormat( + new ConsoleIssueReportFormatSettings + { + GroupByRule = true, + ShowProviderSummary = true, + ShowPrioritySummary = true + }), + repoRootFolder, + string.Empty); +}); +``` diff --git a/docs/input/docs/report-formats/console/features.md b/docs/input/docs/report-formats/console/features.md new file mode 100644 index 000000000..77b9ec143 --- /dev/null +++ b/docs/input/docs/report-formats/console/features.md @@ -0,0 +1,14 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.Reporting.Console addin. +--- +The [Cake.Issues.Reporting.Console addin] provides the following features: + +* Prints issues containing line and column information. +* Group issues by rule +* Reports: + * Number of issues by provider + * Number of issues by priority for every provider and run + +[Cake.Issues.Reporting.Console addin]: https://www.nuget.org/packages/Cake.Issues.Reporting.Console diff --git a/docs/input/docs/report-formats/console/index.cshtml b/docs/input/docs/report-formats/console/index.cshtml new file mode 100644 index 000000000..5003c9001 --- /dev/null +++ b/docs/input/docs/report-formats/console/index.cshtml @@ -0,0 +1,12 @@ +--- +Title: Console +Description: Report format to print issues to the console. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +

+ Support for printing issues to the console is implemented in the + Cake.Issues.Reporting.Console addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/report-formats/console/requirements.md b/docs/input/docs/report-formats/console/requirements.md new file mode 100644 index 000000000..469d4c60c --- /dev/null +++ b/docs/input/docs/report-formats/console/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.Reporting.Console addin. +--- +The requirements for using the [Cake.Issues.Reporting.Console addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.Reporting.Console addin]: https://www.nuget.org/packages/Cake.Issues.Reporting.Console +[release notes]: release-notes \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/examples/custom-template.md b/docs/input/docs/report-formats/generic/examples/custom-template.md new file mode 100644 index 000000000..8f3bbf242 --- /dev/null +++ b/docs/input/docs/report-formats/generic/examples/custom-template.md @@ -0,0 +1,116 @@ +--- +Order: 20 +Title: Custom template +Description: Example how to create a report using a custom template +--- +:::{.alert .alert-info} +If you create a universally usable custom template we're happy to package it with the addin. +To have it included in the addin please [create a pull request] with your contribution. +::: + +The following example will create a HTML report for issues logged as warnings by MsBuild using a custom template. + +:::{.alert .alert-warning} +Please note that you always should pin addins and tools to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the packages. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +```csharp +#tool "nuget:?package=MSBuild.Extension.Pack" +#addin "Cake.Issues" +#addin "Cake.Issues.MsBuild" +#addin "Cake.Issues.Reporting" +#addin "Cake.Issues.Reporting.Generic" + +Task("Create-IssueReport").Does(() => +{ + var repoRootFolder = new DirectoryPath(@"c:\repo"); + + // Build MySolution.sln solution in the repository root folder and log issues + // using XmlFileLogger from MSBuild Extension Pack. + FilePath msBuildLogFile = @"c:\build\msbuild.log"; + var settings = new MsBuildSettings() + .WithLogger( + Context.Tools.Resolve("MSBuild.ExtensionPack.Loggers.dll").FullPath, + "XmlFileLogger", + string.Format( + "logfile=\"{0}\";verbosity=Detailed;encoding=UTF-8", + msBuildLogFile) + ); + MSBuild(repoRootFolder.CombineWithFilePath("MySolution.sln"), settings); + + // Create HTML report using Diagnostic template. + CreateIssueReport( + new List + { + MsBuildIssuesFromFilePath( + msBuildLogFile, + MsBuildXmlFileLoggerFormat) + }, + GenericIssueReportFormatFromFilePath(@"c:\ReportTemplate.cshtml"), + repoRootFolder, + @"c:\report.html"); +}); +``` + +`ReportTemplate` looks like this: + +```csharp +@model IEnumerable + + + + + + + + + + + + + + + + + + + + + + + @foreach (var issue in Model) + { + + + + + + + + + + } + +
AffectedFileRelativePathLineMessagePriorityRuleRuleUrlProviderType
@issue.AffectedFileRelativePath@issue.Line@issue.MessageText@issue.Priority@issue.RuleId@issue.RuleUrl@issue.ProviderType
+ + +``` + +The template retrieves an `IEnumerable` as model. + +:::{.alert .alert-info} +In custom templates functionality from the following assemblies are available: + +* System.dll +* System.Core.dll +* netstandard.dll +* Cake.Core.dll +* Cake.Issues.dll +* Cake.Issues.Reporting.Generic.dll + +::: + +[create a pull request]: https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/CONTRIBUTING.md diff --git a/docs/input/docs/report-formats/generic/examples/default-template.md b/docs/input/docs/report-formats/generic/examples/default-template.md new file mode 100644 index 000000000..7da2601bb --- /dev/null +++ b/docs/input/docs/report-formats/generic/examples/default-template.md @@ -0,0 +1,51 @@ +--- +Order: 10 +Title: Embedded default template +Description: Example how to create a report using an embedded default template. +--- +The following example will create a HTML report for issues logged as warnings by MsBuild. + +:::{.alert .alert-warning} +Please note that you always should pin addins and tools to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the packages. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +```csharp +#tool "nuget:?package=MSBuild.Extension.Pack" +#addin "Cake.Issues" +#addin "Cake.Issues.MsBuild" +#addin "Cake.Issues.Reporting" +#addin "Cake.Issues.Reporting.Generic" + +Task("Create-IssueReport").Does(() => +{ + var repoRootFolder = new DirectoryPath(@"c:\repo"); + + // Build MySolution.sln solution in the repository root folder and log issues + // using XmlFileLogger from MSBuild Extension Pack. + FilePath msBuildLogFile = @"c:\build\msbuild.log"; + var settings = new MsBuildSettings() + .WithLogger( + Context.Tools.Resolve("MSBuild.ExtensionPack.Loggers.dll").FullPath, + "XmlFileLogger", + string.Format( + "logfile=\"{0}\";verbosity=Detailed;encoding=UTF-8", + msBuildLogFile) + ); + MSBuild(repoRootFolder.CombineWithFilePath("MySolution.sln"), settings); + + // Create HTML report using Diagnostic template. + CreateIssueReport( + new List + { + MsBuildIssuesFromFilePath( + msBuildLogFile, + MsBuildXmlFileLoggerFormat) + }, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDiagnostic), + repoRootFolder, + @"c:\report.html"); +}); +``` \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/examples/index.cshtml b/docs/input/docs/report-formats/generic/examples/index.cshtml new file mode 100644 index 000000000..f820e1ac5 --- /dev/null +++ b/docs/input/docs/report-formats/generic/examples/index.cshtml @@ -0,0 +1,7 @@ +--- +Title: Examples +Description: Examples for using the Cake.Issues.Reporting.Generic addin. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/features.md b/docs/input/docs/report-formats/generic/features.md new file mode 100644 index 000000000..247752c6e --- /dev/null +++ b/docs/input/docs/report-formats/generic/features.md @@ -0,0 +1,20 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.Reporting.Generic addin. +--- +The [Cake.Issues.Reporting.Generic addin] provides the following features: + +* Creates reports in any text based format like HTML or Markdown. +* Provides out of the box templates +* Possibility to use custom templates using Razor +* File linking support for different hosting providers (e.g. [GitHub], [Azure DevOps]) + +:::{.alert .alert-info} +See [Template Gallery] for a list of available out of the box and 3rd party templates. +::: + +[Cake.Issues.Reporting.Generic addin]: https://www.nuget.org/packages/Cake.Issues.Reporting.Generic +[Template Gallery]: templates/ +[GitHub]: ../../../api/Cake.Issues.Reporting.Generic/GenericIssueReportFormatAliases/025FE825 +[Azure DevOps]: ../../../api/Cake.Issues.Reporting.Generic/GenericIssueReportFormatAliases/61E51241 diff --git a/docs/input/docs/report-formats/generic/index.cshtml b/docs/input/docs/report-formats/generic/index.cshtml new file mode 100644 index 000000000..801250351 --- /dev/null +++ b/docs/input/docs/report-formats/generic/index.cshtml @@ -0,0 +1,12 @@ +--- +Title: Generic +Description: Report format to create reports in any text based format (HTML, Markdown, ...). +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +

+ Support for creating reports in any text based format like HTML or Markdown is implemented in the + Cake.Issues.Reporting.Generic addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/requirements.md b/docs/input/docs/report-formats/generic/requirements.md new file mode 100644 index 000000000..e5c917073 --- /dev/null +++ b/docs/input/docs/report-formats/generic/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.Reporting.Generic addin. +--- +The requirements for using the [Cake.Issues.Reporting.Generic addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.Reporting.Generic addin]: https://www.nuget.org/packages/Cake.Issues.Reporting.Generic +[release notes]: release-notes \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/.artifactignore b/docs/input/docs/report-formats/generic/templates/.artifactignore new file mode 100644 index 000000000..3c8fd7f2d --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/.artifactignore @@ -0,0 +1,2 @@ +**/* +!*.html \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldatatable-demo-default.html b/docs/input/docs/report-formats/generic/templates/htmldatatable-demo-default.html new file mode 100644 index 000000000..0990eedaf --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldatatable-demo-default.html @@ -0,0 +1,495 @@ + + + + + + + + Issues Report + + + + + + + +

Issues Report

+ + +

MSBuild

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SeverityProjectDirectoryFileLocationRuleMessage
WarningClassLibrary1src/ClassLibrary1CSC + CA9998 + FxCopAnalyzers package has been deprecated in favor of 'Microsoft.CodeAnalysis.NetAnalyzers', that ships with the .NET SDK. Please refer to https://docs.microsoft.com/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers to migrate to .NET analyzers.
WarningClassLibrary1src/ClassLibrary1CSC + CA9998 + FxCopAnalyzers package has been deprecated in favor of 'Microsoft.CodeAnalysis.NetAnalyzers', that ships with the .NET SDK. Please refer to https://docs.microsoft.com/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers to migrate to .NET analyzers.
WarningClassLibrary1src/ClassLibrary1Class1.cs1:1 + SA1633 + The file header is missing or not located at the top of the file.
WarningClassLibrary1src/ClassLibrary1CSC + CA9998 + FxCopAnalyzers package has been deprecated in favor of 'Microsoft.CodeAnalysis.NetAnalyzers', that ships with the .NET SDK. Please refer to https://docs.microsoft.com/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers to migrate to .NET analyzers.
WarningClassLibrary1src/ClassLibrary1Class1.cs1:1 + SA1200 + Using directive should appear within a namespace declaration
WarningClassLibrary1src/ClassLibrary1Class1.cs2:1 + SA1200 + Using directive should appear within a namespace declaration
WarningClassLibrary1src/ClassLibrary1Class1.cs3:1 + SA1200 + Using directive should appear within a namespace declaration
WarningClassLibrary1src/ClassLibrary1Class1.cs4:1 + SA1200 + Using directive should appear within a namespace declaration
WarningClassLibrary1src/ClassLibrary1Class1.cs5:1 + SA1200 + Using directive should appear within a namespace declaration
WarningClassLibrary1src/ClassLibrary1Class1.cs11:21 + CA1822 + Member 'Foo' does not access instance data and can be marked as static
WarningClassLibrary1src/ClassLibrary1Class1.cs21:21 + CA1822 + Member 'Bar' does not access instance data and can be marked as static
WarningClassLibrary1src/ClassLibrary1CSC + SA0001 + XML comment analysis is disabled due to project configuration
+ +

DupFinder

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SeverityProjectDirectoryFileLocationRuleMessage
Warningsrc/ClassLibrary1Class1.cs12-19 +dupFinder Possible duplicate detected (cost 76). The following fragments were found that might be duplicates: "src\ClassLibrary1\Class1.cs" (Line 22 to 29)
Warningsrc/ClassLibrary1Class1.cs22-29 +dupFinder Possible duplicate detected (cost 76). The following fragments were found that might be duplicates: "src\ClassLibrary1\Class1.cs" (Line 12 to 19)
+ +

InspectCode

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SeverityProjectDirectoryFileLocationRuleMessage
WarningClassLibrary1src/ClassLibrary1Class1.cs1 + RedundantUsingDirective + Using directive is not required by the code and can be safely removed
WarningClassLibrary1src/ClassLibrary1Class1.cs2 + RedundantUsingDirective + Using directive is not required by the code and can be safely removed
WarningClassLibrary1src/ClassLibrary1Class1.cs3 + RedundantUsingDirective + Using directive is not required by the code and can be safely removed
WarningClassLibrary1src/ClassLibrary1Class1.cs4 + RedundantUsingDirective + Using directive is not required by the code and can be safely removed
WarningClassLibrary1src/ClassLibrary1Class1.cs5 + RedundantUsingDirective + Using directive is not required by the code and can be safely removed
WarningClassLibrary1src/ClassLibrary1Class1.cs17 + UnusedVariable + Local variable 'foobar' is never used
WarningClassLibrary1src/ClassLibrary1Class1.cs27 + UnusedVariable + Local variable 'foobar' is never used
SuggestionClassLibrary1src/ClassLibrary1Class1.cs9 + UnusedType.Global + Class 'Class1' is never used
SuggestionClassLibrary1src/ClassLibrary1Class1.cs11 + UnusedMember.Global + Method 'Foo' is never used
SuggestionClassLibrary1src/ClassLibrary1Class1.cs21 + UnusedMember.Global + Method 'Bar' is never used
+ +

markdownlint - Demos documentation

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SeverityProjectDirectoryFileLocationRuleMessage
Warningdocsindex.md1 + MD022 + Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "# foo"]
Warningdocsindex.md2:811 + MD009 + Trailing spaces [Expected: 0 or 2; Actual: 1]
Warningdocsindex.md2:101 + MD013 + Line length [Expected: 100; Actual: 811]
Warningdocsindex.md4 + MD022 + Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "# bar"]
Warningdocsindex.md4 + MD025 + Multiple top-level headings in the same document [Context: "# bar"]
Warningdocsindex.md5 + MD031 + Fenced code blocks should be surrounded by blank lines [Context: "```"]
Warningdocsindex.md5 + MD040 + Fenced code blocks should have a language specified [Context: "```"]
Warningdocsindex.md7:3 + MD047 + Files should end with a single newline character
+ +

My Cake Script

+ + + + + + + + + + + + + + + + + + + + + + + +
SeverityProjectDirectoryFileLocationRuleMessage
Warningmyfile.txt42 + Something went wrong
+ + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldatatable.md b/docs/input/docs/report-formats/generic/templates/htmldatatable.md new file mode 100644 index 000000000..68653531b --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldatatable.md @@ -0,0 +1,54 @@ +--- +Order: 20 +Title: HTML Data Table +Description: Template for a HTML report containing a rich data table view with sorting and search functionality. +--- +Template for a HTML report containing a rich data table view with sorting and search functionality powered by [Simple-DataTables]. + +![HTML Data Table](htmldatatable01.png "HTML Data Table") + +# Features + +* Separate table for issues of each issue provider. +* Table with `Severity`, `Project`, `Path`, `File`, `Location`, `Rule`, `Message`. +* Each column sortable by user. +* Paged table with possibility for user to change number of entries per page. +* Client-side full text search. +* No internet access required for displaying. + +# Requirements + +* Cake.Issues.Reporting.Generic 0.2.1 or higher + +# Usage + +To create a report using the HTML Data Table template you can use the [GenericIssueReportTemplate.HtmlDataTable] enum value: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDataTable), + @"c:\repo", + @"c:\report.html"); +``` + +# Options + +This template doesn't support any options. + +# Demos + +* Default + +# Source Code + +:::{.alert .alert-info} +You can use the source code as a template for your [custom template]. +::: + +Source code is available on [GitHub]. + +[Simple-DataTables]: https://github.com/fiduswriter/Simple-DataTables +[GenericIssueReportTemplate.HtmlDataTable]: ../../../../../Cake.Issues.Website/api/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate/62ADE81F +[custom template]: ../examples/custom-template +[GitHub]: https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/src/Cake.Issues.Reporting.Generic/Templates/DataTable.cshtml diff --git a/docs/input/docs/report-formats/generic/templates/htmldatatable01.png b/docs/input/docs/report-formats/generic/templates/htmldatatable01.png new file mode 100644 index 000000000..1ae1fe4a7 Binary files /dev/null and b/docs/input/docs/report-formats/generic/templates/htmldatatable01.png differ diff --git a/docs/input/docs/report-formats/generic/templates/htmldiagnostic-demo-default.html b/docs/input/docs/report-formats/generic/templates/htmldiagnostic-demo-default.html new file mode 100644 index 000000000..d4d6809cb --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldiagnostic-demo-default.html @@ -0,0 +1,698 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProjectFileRelativePathProjectNameAffectedFileRelativePathLineEndLineColumnEndColumnMessageTextMessageHtmlMessageMarkdownPriorityPriorityNameRuleIdRuleNameRuleUrlRunProviderTypeProviderName
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/CSCFxCopAnalyzers package has been deprecated in favor of 'Microsoft.CodeAnalysis.NetAnalyzers', that ships with the .NET SDK. Please refer to https://docs.microsoft.com/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers to migrate to .NET analyzers.300WarningCA9998https://www.google.com/search?q="CA9998:"+site:learn.microsoft.comCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/CSCFxCopAnalyzers package has been deprecated in favor of 'Microsoft.CodeAnalysis.NetAnalyzers', that ships with the .NET SDK. Please refer to https://docs.microsoft.com/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers to migrate to .NET analyzers.300WarningCA9998https://www.google.com/search?q="CA9998:"+site:learn.microsoft.comCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs11The file header is missing or not located at the top of the file.300WarningSA1633https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1633.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/CSCFxCopAnalyzers package has been deprecated in favor of 'Microsoft.CodeAnalysis.NetAnalyzers', that ships with the .NET SDK. Please refer to https://docs.microsoft.com/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers to migrate to .NET analyzers.300WarningCA9998https://www.google.com/search?q="CA9998:"+site:learn.microsoft.comCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs11Using directive should appear within a namespace declaration300WarningSA1200https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs21Using directive should appear within a namespace declaration300WarningSA1200https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs31Using directive should appear within a namespace declaration300WarningSA1200https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs41Using directive should appear within a namespace declaration300WarningSA1200https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs51Using directive should appear within a namespace declaration300WarningSA1200https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs1121Member 'Foo' does not access instance data and can be marked as static300WarningCA1822https://www.google.com/search?q="CA1822:"+site:learn.microsoft.comCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/Class1.cs2121Member 'Bar' does not access instance data and can be marked as static300WarningCA1822https://www.google.com/search?q="CA1822:"+site:learn.microsoft.comCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/ClassLibrary1.csprojClassLibrary1src/ClassLibrary1/CSCXML comment analysis is disabled due to project configuration300WarningSA0001https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA0001.mdCake.Issues.MsBuild.MsBuildIssuesProviderMSBuild
src/ClassLibrary1/Class1.cs1219Possible duplicate detected (cost 76). The following fragments were found that might be duplicates: "src\ClassLibrary1\Class1.cs" (Line 22 to 29)Possible duplicate detected (cost 76).<br/>The following fragments were found that might be duplicates:<br/><a href='https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/demos/script-runner/src/ClassLibrary1/Class1.cs#L22-L29'>src\ClassLibrary1\Class1.cs</a> (Line 22 to 29)Possible duplicate detected (cost 76). The following fragments were found that might be duplicates: [src\ClassLibrary1\Class1.cs](https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/demos/script-runner/src/ClassLibrary1/Class1.cs#L22-L29) (Line 22 to 29)300WarningdupFinderCake.Issues.DupFinder.DupFinderIssuesProviderDupFinder
src/ClassLibrary1/Class1.cs2229Possible duplicate detected (cost 76). The following fragments were found that might be duplicates: "src\ClassLibrary1\Class1.cs" (Line 12 to 19)Possible duplicate detected (cost 76).<br/>The following fragments were found that might be duplicates:<br/><a href='https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/demos/script-runner/src/ClassLibrary1/Class1.cs#L12-L19'>src\ClassLibrary1\Class1.cs</a> (Line 12 to 19)Possible duplicate detected (cost 76). The following fragments were found that might be duplicates: [src\ClassLibrary1\Class1.cs](https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/demos/script-runner/src/ClassLibrary1/Class1.cs#L12-L19) (Line 12 to 19)300WarningdupFinderCake.Issues.DupFinder.DupFinderIssuesProviderDupFinder
ClassLibrary1src/ClassLibrary1/Class1.cs1Using directive is not required by the code and can be safely removed300WarningRedundantUsingDirectiveRedundant using directivehttps://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirectiveCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs2Using directive is not required by the code and can be safely removed300WarningRedundantUsingDirectiveRedundant using directivehttps://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirectiveCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs3Using directive is not required by the code and can be safely removed300WarningRedundantUsingDirectiveRedundant using directivehttps://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirectiveCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs4Using directive is not required by the code and can be safely removed300WarningRedundantUsingDirectiveRedundant using directivehttps://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirectiveCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs5Using directive is not required by the code and can be safely removed300WarningRedundantUsingDirectiveRedundant using directivehttps://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirectiveCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs9Class 'Class1' is never used200SuggestionUnusedType.GlobalType is never used: Non-private accessibilityhttps://www.jetbrains.com/resharperplatform/help?Keyword=UnusedType.GlobalCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs11Method 'Foo' is never used200SuggestionUnusedMember.GlobalType member is never used: Non-private accessibilityhttps://www.jetbrains.com/resharperplatform/help?Keyword=UnusedMember.GlobalCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs17Local variable 'foobar' is never used300WarningUnusedVariableUnused local variablehttps://www.jetbrains.com/resharperplatform/help?Keyword=UnusedVariableCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs21Method 'Bar' is never used200SuggestionUnusedMember.GlobalType member is never used: Non-private accessibilityhttps://www.jetbrains.com/resharperplatform/help?Keyword=UnusedMember.GlobalCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
ClassLibrary1src/ClassLibrary1/Class1.cs27Local variable 'foobar' is never used300WarningUnusedVariableUnused local variablehttps://www.jetbrains.com/resharperplatform/help?Keyword=UnusedVariableCake.Issues.InspectCode.InspectCodeIssuesProviderInspectCode
docs/index.md1Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "# foo"]300WarningMD022https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md022Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md2811Trailing spaces [Expected: 0 or 2; Actual: 1]300WarningMD009https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md009Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md2101Line length [Expected: 100; Actual: 811]300WarningMD013https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md013Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md4Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "# bar"]300WarningMD022https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md022Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md4Multiple top-level headings in the same document [Context: "# bar"]300WarningMD025https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md025Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md5Fenced code blocks should be surrounded by blank lines [Context: "```"]300WarningMD031https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md031Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md5Fenced code blocks should have a language specified [Context: "```"]300WarningMD040https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md040Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
docs/index.md73Files should end with a single newline character300WarningMD047https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md047Demos documentationCake.Issues.Markdownlint.MarkdownlintIssuesProvidermarkdownlint
myfile.txt42Something went wrongSomething went <b>wrong</b>Something went **wrong**300WarningMyCakeScriptMy Cake Script
+ + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldiagnostic.md b/docs/input/docs/report-formats/generic/templates/htmldiagnostic.md new file mode 100644 index 000000000..8e3b8f023 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldiagnostic.md @@ -0,0 +1,50 @@ +--- +Order: 30 +Title: HTML Diagnostic +Description: Template for a HTML report containing a list of all issues with all properties. +--- +Template for a HTML report containing a list of all issues with all properties. + +![HTML Diagnostic](htmldiagnostic01.png "HTML Diagnostic") + +# Features + +* Unstyled table listing all properties of [IIssue] +* No internet access required for displaying. + +# Requirements + +* No additional requirements. + +# Usage + +To create a report using the HTML diagnostic template you can use the [GenericIssueReportTemplate.HtmlDiagnostic] enum value: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDiagnostic), + @"c:\repo", + @"c:\report.html"); +``` + +# Options + +This template doesn't support any options. + +# Demos + +* Default + +# Source Code + +:::{.alert .alert-info} +You can use the source code as a template for your [custom template]. +::: + +Source code is available on [GitHub]. + +[IIssue]: ../../../../../Cake.Issues.Website/api/Cake.Issues/IIssue/ +[GenericIssueReportTemplate.HtmlDiagnostic]: ../../../../../Cake.Issues.Website/api/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate/4F88BD05 +[custom template]: ../examples/custom-template +[GitHub]: https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/src/Cake.Issues.Reporting.Generic/Templates/Diagnostic.cshtml \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldiagnostic01.png b/docs/input/docs/report-formats/generic/templates/htmldiagnostic01.png new file mode 100644 index 000000000..5a011546b Binary files /dev/null and b/docs/input/docs/report-formats/generic/templates/htmldiagnostic01.png differ diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-additionalcolumns.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-additionalcolumns.html new file mode 100644 index 000000000..5a05ce70e --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-additionalcolumns.html @@ -0,0 +1,222 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-changetitle.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-changetitle.html new file mode 100644 index 000000000..7d1f76f05 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-changetitle.html @@ -0,0 +1,213 @@ + + + + + + + + + + My Custom Title + + + + + + + + + +

My Custom Title

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-columnhiding.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-columnhiding.html new file mode 100644 index 000000000..4ba2e08da --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-columnhiding.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-customexportfilename.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-customexportfilename.html new file mode 100644 index 000000000..a86ec6554 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-customexportfilename.html @@ -0,0 +1,233 @@ + + + + + + + + + + Issues Report + + + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-customscriptlocation.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-customscriptlocation.html new file mode 100644 index 000000000..07f23a451 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-customscriptlocation.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-default.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-default.html new file mode 100644 index 000000000..4ba2e08da --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-default.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablefiltering.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablefiltering.html new file mode 100644 index 000000000..644a0ff85 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablefiltering.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablegrouping.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablegrouping.html new file mode 100644 index 000000000..a1ea0b0cb --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablegrouping.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disableheader.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disableheader.html new file mode 100644 index 000000000..25a075434 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disableheader.html @@ -0,0 +1,212 @@ + + + + + + + + + + Issues Report + + + + + + + + + + +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablesearching.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablesearching.html new file mode 100644 index 000000000..e4c1a4126 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-disablesearching.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-enableexporting.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-enableexporting.html new file mode 100644 index 000000000..33f9168e0 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-enableexporting.html @@ -0,0 +1,233 @@ + + + + + + + + + + Issues Report + + + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-exportformat-pdf.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-exportformat-pdf.html new file mode 100644 index 000000000..88ad0d356 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-exportformat-pdf.html @@ -0,0 +1,235 @@ + + + + + + + + + + Issues Report + + + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-exportformat-xlsx.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-exportformat-xlsx.html new file mode 100644 index 000000000..33f9168e0 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-exportformat-xlsx.html @@ -0,0 +1,233 @@ + + + + + + + + + + Issues Report + + + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-grouping.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-grouping.html new file mode 100644 index 000000000..d3e057ce8 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-grouping.html @@ -0,0 +1,212 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-sorting.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-sorting.html new file mode 100644 index 000000000..254eeb36e --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-sorting.html @@ -0,0 +1,207 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-carmine.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-carmine.html new file mode 100644 index 000000000..b3125bc6a --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-carmine.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-contrast.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-contrast.html new file mode 100644 index 000000000..9f3eb4da5 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-contrast.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-contrastcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-contrastcompact.html new file mode 100644 index 000000000..d5901ce66 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-contrastcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-dark.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-dark.html new file mode 100644 index 000000000..e855065fa --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-dark.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkcompact.html new file mode 100644 index 000000000..97d2b50da --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkmoon.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkmoon.html new file mode 100644 index 000000000..a4301993b --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkmoon.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkviolet.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkviolet.html new file mode 100644 index 000000000..90885126b --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-darkviolet.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-greenmist.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-greenmist.html new file mode 100644 index 000000000..067f30348 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-greenmist.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-light.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-light.html new file mode 100644 index 000000000..4ba2e08da --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-light.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-lightcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-lightcompact.html new file mode 100644 index 000000000..94d65c3d0 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-lightcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluedark.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluedark.html new file mode 100644 index 000000000..df855737d --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluedark.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluedarkcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluedarkcompact.html new file mode 100644 index 000000000..ee52b9494 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluedarkcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluelight.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluelight.html new file mode 100644 index 000000000..a44a4375a --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluelight.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluelightcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluelightcompact.html new file mode 100644 index 000000000..e375faa9b --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialbluelightcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimedark.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimedark.html new file mode 100644 index 000000000..a6197a45b --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimedark.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimedarkcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimedarkcompact.html new file mode 100644 index 000000000..ba5d6dbfe --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimedarkcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimelight.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimelight.html new file mode 100644 index 000000000..9d92710df --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimelight.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimelightcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimelightcompact.html new file mode 100644 index 000000000..3a000e847 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materiallimelightcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangedark.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangedark.html new file mode 100644 index 000000000..692836f26 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangedark.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangedarkcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangedarkcompact.html new file mode 100644 index 000000000..80ef7cec7 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangedarkcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangelight.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangelight.html new file mode 100644 index 000000000..1b3031eaa --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangelight.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangelightcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangelightcompact.html new file mode 100644 index 000000000..61c7a2941 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialorangelightcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurpledark.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurpledark.html new file mode 100644 index 000000000..bb0cb9f26 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurpledark.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurpledarkcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurpledarkcompact.html new file mode 100644 index 000000000..9465f504c --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurpledarkcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurplelight.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurplelight.html new file mode 100644 index 000000000..4f09be5f3 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurplelight.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurplelightcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurplelightcompact.html new file mode 100644 index 000000000..f90659179 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialpurplelightcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialtealdark.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialtealdark.html new file mode 100644 index 000000000..c8aa1d0cb --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialtealdark.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialtealdarkcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialtealdarkcompact.html new file mode 100644 index 000000000..39bdd6e5e --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialtealdarkcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialteallight.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialteallight.html new file mode 100644 index 000000000..e09486a06 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialteallight.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialteallightcompact.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialteallightcompact.html new file mode 100644 index 000000000..2c67bd2d2 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-materialteallightcompact.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-softblue.html b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-softblue.html new file mode 100644 index 000000000..34a622c5b --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid-demo-theme-softblue.html @@ -0,0 +1,213 @@ + + + + + + + + + + Issues Report + + + + + + + + + +

Issues Report

+ +
+
+
+ + + + + + \ No newline at end of file diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid.md b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid.md new file mode 100644 index 000000000..d0745306a --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid.md @@ -0,0 +1,240 @@ +--- +Order: 10 +Title: HTML DevExtreme Data Grid +Description: Template for a HTML report containing a rich data grid with sorting, filtering, grouping and search capabilities. +--- +Template for a HTML report containing a rich data grid with sorting, filtering, grouping and search capabilities powered by [DevExtreme]. + +![HTML DevExtreme Data Grid](htmldxdatagrid01.png "HTML DevExtreme Data Grid") + +# Features + +* Table with `Provider`, `Severity`, `Project`, `Path`, `File`, `Location`, `Rule`, `Message` by default. +* Support for grouping by multiple columns by user. +* Total number of issues by each group level. +* Each column sortable by user. +* Data can be filtered by any column by user. +* Paged view. +* Client-side full text search. +* Client-side export to Microsoft Excel or PDF. +* Fully customizable through [options](#options). + +# Requirements + +* Cake.Issues.Reporting.Generic 0.3.1 or higher + +# Usage + +To create a report using the HTML DevExtreme Data Grid template you can use the [GenericIssueReportTemplate.HtmlDxDataGrid] enum value: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDxDataGrid), + @"c:\repo", + @"c:\report.html"); +``` + +# Options + +See [HtmlDxDataGridOption] for a list of possible options. + +# Demos + +The following demo shows the template with its default options: + +* Default + (Source Code) + +## Themes + +The template supports the teams defined in the [DevExtremeTheme] enumeration which can be set using the [HtmlDxDataGridOption.Theme]: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings.WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLight)), + @"c:\repo", + @"c:\report.html"); +``` + +* Light Theme + (Source Code) +* Dark Theme + (Source Code) +* Contrast Theme + (Source Code) +* Carmine Theme + (Source Code) +* Dark Moon Theme + (Source Code) +* Soft Blue Theme + (Source Code) +* Dark Violet Theme + (Source Code) +* Green Mist Theme + (Source Code) +* Light Compact Theme + (Source Code) +* Dark Compact Theme + (Source Code) +* Contrast Compact Theme + (Source Code) +* Material Blue Light Theme + (Source Code) +* Material Lime Light Theme + (Source Code) +* Material Orange Light Theme + (Source Code) +* Material Purple Light Theme + (Source Code) +* Material Teal Light Theme + (Source Code) +* Material Blue Dark Theme + (Source Code) +* Material Lime Dark Theme + (Source Code) +* Material Orange Dark Theme + (Source Code) +* Material Purple Dark Theme + (Source Code) +* Material Teal Dark Theme + (Source Code) +* Material Blue Light Compact Theme + (Source Code) +* Material Lime Light Compact Theme + (Source Code) +* Material Orange Light Compact Theme + (Source Code) +* Material Purple Light Compact Theme + (Source Code) +* Material Teal Light Compact Theme + (Source Code) +* Material Blue Dark Compact Theme + (Source Code) +* Material Lime Dark Compact Theme + (Source Code) +* Material Orange Dark Compact Theme + (Source Code) +* Material Purple Dark Compact Theme + (Source Code) +* Material Teal Dark Compact Theme + (Source Code) + +## Column visibility + +Visible columns can be defined using the `ColumnNameVisible` option: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings.WithOption(HtmlDxDataGridOption.LineVisible, false)), + @"c:\repo", + @"c:\report.html"); +``` + +Additional columns can be added using the [HtmlDxDataGridOption.AdditionalColumns] option. + +* Show and hide columns + (Source Code) +* Add additional columns + (Source Code) + +## Sorting + +Sorted columns can be defined using the [HtmlDxDataGridOption.SortedColumns] and the +`ColumnNameSortOder` options: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.SortedColumns, new List { ReportColumn.RuleId }) + .WithOption(HtmlDxDataGridOption.RuleIdSortOder, ColumnSortOderDescending )), + @"c:\repo", + @"c:\report.html"); +``` + +* Change sorting + (Source Code) + +## Grouping + +Grouping can be defined using the [HtmlDxDataGridOption.GroupedColumns] option: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings.WithOption(HtmlDxDataGridOption.GroupedColumns, new List { ReportColumn.RuleId })), + @"c:\repo", + @"c:\report.html"); +``` + +* Change grouping + (Source Code) +* Disable grouping + (Source Code) + +## Exporting + +Exporting can be enabled using the [HtmlDxDataGridOption.EnableExporting] option: + +```csharp +CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings.WithOption(HtmlDxDataGridOption.EnableExporting, true)), + @"c:\repo", + @"c:\report.html"); +``` + +* Enable exporting + (Source Code) +* Microsoft Excel export (*.xlsx) + (Source Code) +* PDF export (*.pdf) + (Source Code) +* Custom export file name + (Source Code) + +## Other features + +* Change title + (Source Code) +* Disable header + (Source Code) +* Disable filtering + (Source Code) +* Disable searching + (Source Code) +* Custom script location and version + (Source Code) + +# Source Code + +:::{.alert .alert-info} +You can use the source code as a template for your [custom template]. +::: + +Source code is available on [GitHub]. + +[DevExtreme]: https://js.devexpress.com +[GenericIssueReportTemplate.HtmlDxDataGrid]: ../../../../../api/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate/0E9E9D94 +[HtmlDxDataGridOption]: ../../../../../api/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption/ +[DevExtremeTheme]: ../../../../../api/Cake.Issues.Reporting.Generic/DevExtremeTheme/ +[HtmlDxDataGridOption.Theme]: ../../../../../api/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption/EA83DCAB +[HtmlDxDataGridOption.AdditionalColumns]: ../../../../../api/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption/F9860912 +[HtmlDxDataGridOption.SortedColumns]: ../../../../../api/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption/D578E453 +[HtmlDxDataGridOption.GroupedColumns]: ../../../../../api/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption/0907599C +[HtmlDxDataGridOption.EnableExporting]: ../../../../../api/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption/1441E285 +[custom template]: ../examples/custom-template +[GitHub]: https://github.com/cake-contrib/Cake.Issues.Reporting.Generic/blob/develop/src/Cake.Issues.Reporting.Generic/Templates/DxDataGrid.cshtml diff --git a/docs/input/docs/report-formats/generic/templates/htmldxdatagrid01.png b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid01.png new file mode 100644 index 000000000..aaaa90e90 Binary files /dev/null and b/docs/input/docs/report-formats/generic/templates/htmldxdatagrid01.png differ diff --git a/docs/input/docs/report-formats/generic/templates/index.cshtml b/docs/input/docs/report-formats/generic/templates/index.cshtml new file mode 100644 index 000000000..b7e0cc3c3 --- /dev/null +++ b/docs/input/docs/report-formats/generic/templates/index.cshtml @@ -0,0 +1,7 @@ +--- +Title: Template Gallery +Description: Gallery of available out of the box and 3rd party templates. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/report-formats/sarif/examples.md b/docs/input/docs/report-formats/sarif/examples.md new file mode 100644 index 000000000..31b231753 --- /dev/null +++ b/docs/input/docs/report-formats/sarif/examples.md @@ -0,0 +1,51 @@ +--- +Order: 30 +Title: Examples +Description: Examples for using the Cake.Issues.Reporting.Sarif addin. +--- +The following example will create a SARIF report for issues logged as warnings by MsBuild. + +:::{.alert .alert-warning} +Please note that you always should pin addins and tools to a specific version to make sure your builds are deterministic and +won't break due to updates to one of the packages. + +See [pinning addin versions](https://cakebuild.net/docs/tutorials/pinning-cake-version#pinning-addin-version) for details. +::: + +```csharp +#tool "nuget:?package=MSBuild.Extension.Pack" +#addin "Cake.Issues" +#addin "Cake.Issues.MsBuild" +#addin "Cake.Issues.Reporting" +#addin "Cake.Issues.Reporting.Sarif" + +Task("Create-IssueReport").Does(() => +{ + var repoRootFolder = new DirectoryPath(@"c:\repo"); + + // Build MySolution.sln solution in the repository root folder and log issues + // using XmlFileLogger from MSBuild Extension Pack. + FilePath msBuildLogFile = @"c:\build\msbuild.log"; + var settings = new MsBuildSettings() + .WithLogger( + Context.Tools.Resolve("MSBuild.ExtensionPack.Loggers.dll").FullPath, + "XmlFileLogger", + string.Format( + "logfile=\"{0}\";verbosity=Detailed;encoding=UTF-8", + msBuildLogFile) + ); + MSBuild(repoRootFolder.CombineWithFilePath("MySolution.sln"), settings); + + // Create SARIF report. + CreateIssueReport( + new List + { + MsBuildIssuesFromFilePath( + msBuildLogFile, + MsBuildXmlFileLoggerFormat) + }, + SarifIssueReportFormat(), + repoRootFolder, + @"c:\report.sarif"); +}); +``` \ No newline at end of file diff --git a/docs/input/docs/report-formats/sarif/features.md b/docs/input/docs/report-formats/sarif/features.md new file mode 100644 index 000000000..b2ab2de32 --- /dev/null +++ b/docs/input/docs/report-formats/sarif/features.md @@ -0,0 +1,17 @@ +--- +Order: 20 +Title: Features +Description: Features of the Cake.Issues.Reporting.Sarif addin. +--- +The [Cake.Issues.Reporting.Sarif addin] provides the following features: + +* Creates SARIF compatible files. +* Supports the following properties in the SARIF report: + * RuleId + * Message + * Kind + * Level + * Location + * RuleUrl + +[Cake.Issues.Reporting.Sarif addin]: https://www.nuget.org/packages/Cake.Issues.Reporting.Sarif diff --git a/docs/input/docs/report-formats/sarif/index.cshtml b/docs/input/docs/report-formats/sarif/index.cshtml new file mode 100644 index 000000000..55d163ac7 --- /dev/null +++ b/docs/input/docs/report-formats/sarif/index.cshtml @@ -0,0 +1,12 @@ +--- +Title: Sarif +Description: Report format to create SARIF compatible reports. +--- +

@Html.Raw(Model.String(DocsKeys.Description))

+ +

+ Support for creating SARIF compatible reports is implemented in the + Cake.Issues.Reporting.Sarif addin. +

+ +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/report-formats/sarif/requirements.md b/docs/input/docs/report-formats/sarif/requirements.md new file mode 100644 index 000000000..ab7342854 --- /dev/null +++ b/docs/input/docs/report-formats/sarif/requirements.md @@ -0,0 +1,9 @@ +--- +Order: 10 +Title: Requirements +Description: Requirements for the Cake.Issues.Reporting.Sarif addin. +--- +The requirements for using the [Cake.Issues.Reporting.Sarif addin] are listed in the [release notes] for any specific version. + +[Cake.Issues.Reporting.Sarif addin]: https://www.nuget.org/packages/Cake.Issues.Reporting.Sarif +[release notes]: release-notes \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.DocFx.nuspec b/nuspec/nuget/Cake.Frosting.Issues.DocFx.nuspec new file mode 100644 index 000000000..317591ecd --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.DocFx.nuspec @@ -0,0 +1,59 @@ + + + + Cake.Frosting.Issues.DocFx + Cake.Frosting.Issues.DocFx + 0.0.0 + Cake Issues contributors + bbtsoftware, pascalberger, cake-contrib + DocFx support for the Cake.Issues addin for Cake Frosting + +The DocFx support for the Cake.Issues addin for Cake allows you to read warnings from DocFx log files. + +This addin provides the aliases for reading warnings from DocFx log files and provides them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.DocFx. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider linting docfx + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.EsLint.nuspec b/nuspec/nuget/Cake.Frosting.Issues.EsLint.nuspec new file mode 100644 index 000000000..a3814124a --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.EsLint.nuspec @@ -0,0 +1,59 @@ + + + + Cake.Frosting.Issues.EsLint + Cake.Frosting.Issues.EsLint + 0.0.0 + Cake Issues contributors + bbtsoftware, pascalberger, cake-contrib + ESLint support for the Cake.Issues addin for Cake Frosting + +The EsLint support for the Cake.Issues addin for Cake allows you to read issues logged by ESLint. + +This addin provides the aliases for reading ESLint issues and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.EsLint. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider code-analysis javascript linting eslint + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.GitRepository.nuspec b/nuspec/nuget/Cake.Frosting.Issues.GitRepository.nuspec new file mode 100644 index 000000000..7365202f1 --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.GitRepository.nuspec @@ -0,0 +1,59 @@ + + + + Cake.Frosting.Issues.GitRepository + Cake.Frosting.Issues.GitRepository + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Git repository linting support for the Cake.Issues addin for Cake Frosting + +The Git repository support for the Cake.Issues addin for Cake allows you to analyze Git repositories. + +This addin provides the aliases for analyzing Git repositories and create issues resulting from it using the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.GitRepository. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider code-analysis linting git + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.InspectCode.nuspec b/nuspec/nuget/Cake.Frosting.Issues.InspectCode.nuspec new file mode 100644 index 000000000..e29b23f17 --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.InspectCode.nuspec @@ -0,0 +1,59 @@ + + + + Cake.Frosting.Issues.InspectCode + Cake.Frosting.Issues.InspectCode + 0.0.0 + Cake Issues contributors + bbtsoftware, pascalberger, cake-contrib + JetBrains Inspect Code support for the Cake.Issues addin for Cake Frosting + +The JetBrains Inspect Code support for the Cake.Issues addin for Cake allows you to read issues logged by JetBrains Inspect Code. + +This addin provides the aliases for reading JetBrains Inspect Code issues and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.InspectCode. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider codeanalysis linting inspectcode + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.Markdownlint.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Markdownlint.nuspec new file mode 100644 index 000000000..48376e6aa --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.Markdownlint.nuspec @@ -0,0 +1,59 @@ + + + + Cake.Frosting.Issues.Markdownlint + Cake.Frosting.Issues.Markdownlint + 0.0.0 + Cake Issues contributors + bbtsoftware, pascalberger, cake-contrib + Markdownlint support for the Cake.Issues addin for Cake Frosting + +The Markdownlint support for the Cake.Issues addin for Cake allows you to read issues logged by Markdownlint. + +This addin provides the aliases for reading Markdownlint issues and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.Markdownlint. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider linting markdown markdownlint + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.MsBuild.nuspec b/nuspec/nuget/Cake.Frosting.Issues.MsBuild.nuspec index a95b4673a..11decdea6 100644 --- a/nuspec/nuget/Cake.Frosting.Issues.MsBuild.nuspec +++ b/nuspec/nuget/Cake.Frosting.Issues.MsBuild.nuspec @@ -29,7 +29,7 @@ For addin compatible with Cake Script Runners see Cake.Issues.MsBuild. Copyright © Cake Issues contributors cake cake-addin cake-issues cake-issueprovider code-analysis linting msbuild - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Frosting.Issues.PullRequests.AppVeyor.nuspec b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.AppVeyor.nuspec new file mode 100644 index 000000000..6ea628c6f --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.AppVeyor.nuspec @@ -0,0 +1,60 @@ + + + + Cake.Frosting.Issues.PullRequests.AppVeyor + Cake.Frosting.Issues.PullRequests.AppVeyor + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + AppVeyor support for the Cake.Issues addin for Cake Frosting + +AppVeyor support for the Cake.Issues addin for Cake allows you to write found issues as message to AppVeyor builds. + +This addin provides the aliases for writing to AppVeyor builds. +It also requires the core Cake.Issues and Cake.Issues.PullRequests addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.PullRequests.AppVeyor. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-pullrequestsystem issues pullrequest buildserver appveyor + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.PullRequests.AzureDevOps.nuspec b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.AzureDevOps.nuspec new file mode 100644 index 000000000..d9214eeef --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.AzureDevOps.nuspec @@ -0,0 +1,64 @@ + + + + Cake.Frosting.Issues.PullRequests.AzureDevOps + Cake.Frosting.Issues.PullRequests.AzureDevOps + 0.0.0 + Cake Issues contributors + bbtsoftware, pascalberger, cake-contrib + Azure DevOps support for the Cake.Issues addin for Cake Frosting + +The Azure DevOps support for the Cake.Issues addin for Cake Frosting allows you to +write found issues as comments to Azure DevOps pull requests. + +This addin provides the aliases for writing to Azure DevOps pull requests. +It also requires the core Cake.Issues and Cake.Issues.PullRequests addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.PullRequests.AzureDevOps. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-pullrequestsystem issues pullrequest tfs azure-devops azure-devops-server + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.PullRequests.GitHubActions.nuspec b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.GitHubActions.nuspec new file mode 100644 index 000000000..a00ebba1b --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.GitHubActions.nuspec @@ -0,0 +1,60 @@ + + + + Cake.Frosting.Issues.PullRequests.GitHubActions + Cake.Frosting.Issues.PullRequests.GitHubActions + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + GitHub Actions support for the Cake.Issues addin for Cake Frosting + +GitHub Actions support for the Cake.Issues addin for Cake allows you to report to GitHub Actions builds. + +This addin provides the aliases for writing to GitHub Actions builds. +It also requires the core Cake.Issues and Cake.Issues.PullRequests addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.PullRequests.GitHubActions. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-pullrequestsystem issues pullrequest buildserver github github-actions + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.PullRequests.nuspec b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.nuspec index 52d873ff0..8e65532b7 100644 --- a/nuspec/nuget/Cake.Frosting.Issues.PullRequests.nuspec +++ b/nuspec/nuget/Cake.Frosting.Issues.PullRequests.nuspec @@ -26,7 +26,7 @@ For addin compatible with Cake Script Runners see Cake.Issues.PullRequests. Copyright © Cake Issues contributors Cake Script Cake-Issues CodeAnalysis Linting Issues Pull-Requests - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Frosting.Issues.Reporting.Console.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Reporting.Console.nuspec new file mode 100644 index 000000000..c58740716 --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.Reporting.Console.nuspec @@ -0,0 +1,65 @@ + + + + Cake.Frosting.Issues.Reporting.Console + Cake.Frosting.Issues.Reporting.Console + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for reporting issues to console for the Cake.Issues addin for Cake Frosting + +The addin for the Cake.Issues addin for Cake Frosting allows you to print issues to the console. + +This addin provides the aliases for reporting issues to the console. +It also requires the core Cake.Issues and Cake.Issues.Reporting addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.Reporting.Console. + +The addin requires Cake Frosting 1.2.0 or higher. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-reportformat issues reporting console + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.Reporting.Generic.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Reporting.Generic.nuspec new file mode 100644 index 000000000..7fbba1396 --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.Reporting.Generic.nuspec @@ -0,0 +1,60 @@ + + + + Cake.Frosting.Issues.Reporting.Generic + Cake.Frosting.Issues.Reporting.Generic + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for creating any reports in any text based format (HTML, Markdown, ...) for the Cake.Issues addin for Cake Frosting + +The generic report support for the Cake.Issues addin for Cake Frosting allows you to create issue reports in any text format (HTML, Markdown, ...). + +This addin provides the aliases for any text based report format. +It also requires the core Cake.Issues and Cake.Issues.Reporting addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.Reporting.Generic. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-reportformat issues reporting html markdown razor + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nuspec/nuget/Cake.Frosting.Issues.Reporting.Sarif.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Reporting.Sarif.nuspec new file mode 100644 index 000000000..ea5cabec2 --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.Reporting.Sarif.nuspec @@ -0,0 +1,63 @@ + + + + Cake.Frosting.Issues.Reporting.Sarif + Cake.Frosting.Issues.Reporting.Sarif + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for creating SARIF compatible files for the Cake.Issues addin for Cake Frosting + +The SARIF support for the Cake.Issues addin for Cake allows you to create SARIF compatible files. + +This addin provides the aliases for creating SARIF compatible files. +It also requires the core Cake.Issues and Cake.Issues.Reporting addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.Reporting.Sarif. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-reportformat issues reporting sarif + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nuspec/nuget/Cake.Frosting.Issues.Reporting.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Reporting.nuspec index 3f1692777..adcbe6aa8 100644 --- a/nuspec/nuget/Cake.Frosting.Issues.Reporting.nuspec +++ b/nuspec/nuget/Cake.Frosting.Issues.Reporting.nuspec @@ -1,8 +1,8 @@ - Cake.Issues.Reporting - Cake.Issues.Reporting + Cake.Frosting.Issues.Reporting + Cake.Frosting.Issues.Reporting 0.0.0 Cake Issues contributors bbtsoftware, pascalberger, cake-contrib @@ -26,7 +26,7 @@ For addin compatible with Cake Script Runners see Cake.Issues.Reporting. Copyright © Cake Issues contributors Cake Script Cake-Issues CodeAnalysis Linting Issues Reporting - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Frosting.Issues.Sarif.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Sarif.nuspec new file mode 100644 index 000000000..caeb7566f --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.Sarif.nuspec @@ -0,0 +1,62 @@ + + + + Cake.Frosting.Issues.Sarif + Cake.Frosting.Issues.Sarif + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for reading SARIF compatible files using the Cake.Issues addin for Cake Frosting + +The SARIF support for the Cake.Issues addin for Cake allows you to read SARIF compatible files. + +This addin provides the aliases for reading issues from SARIF compatible files and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.Sarif. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider linting sarif + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Frosting.Issues.Terraform.nuspec b/nuspec/nuget/Cake.Frosting.Issues.Terraform.nuspec new file mode 100644 index 000000000..487d98dba --- /dev/null +++ b/nuspec/nuget/Cake.Frosting.Issues.Terraform.nuspec @@ -0,0 +1,59 @@ + + + + Cake.Frosting.Issues.Terraform + Cake.Frosting.Issues.Terraform + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Terraform support for the Cake.Issues addin for Cake Frosting + +The Terraform support for the Cake.Issues addin for Cake allows you to read issues logged by terraform validate. + +This addin provides the aliases for reading terraform validate output and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Frosting. +For addin compatible with Cake Script Runners see Cake.Issues.Terraform. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider linting terraform + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.DocFx.nuspec b/nuspec/nuget/Cake.Issues.DocFx.nuspec index 4498302a8..b57bea857 100644 --- a/nuspec/nuget/Cake.Issues.DocFx.nuspec +++ b/nuspec/nuget/Cake.Issues.DocFx.nuspec @@ -16,6 +16,10 @@ It also requires the core Cake.Issues addin. There are also additional addins for generating reports or posting issues to pull requests. See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.DocFx. MIT https://cakeissues.net @@ -24,7 +28,7 @@ See the Project Site for an overview of the whole ecosystem of addins for workin Copyright © Cake Issues contributors cake cake-addin cake-issues cake-issueprovider linting docfx - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.EsLint.nuspec b/nuspec/nuget/Cake.Issues.EsLint.nuspec index 27f46cf33..b33f56499 100644 --- a/nuspec/nuget/Cake.Issues.EsLint.nuspec +++ b/nuspec/nuget/Cake.Issues.EsLint.nuspec @@ -16,6 +16,10 @@ It also requires the core Cake.Issues addin. There are also additional addins for generating reports or posting issues to pull requests. See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.EsLint. MIT https://cakeissues.net @@ -24,7 +28,7 @@ See the Project Site for an overview of the whole ecosystem of addins for workin Copyright © Cake Issues contributors cake cake-addin cake-issues cake-issueprovider code-analysis javascript linting eslint - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.GitRepository.nuspec b/nuspec/nuget/Cake.Issues.GitRepository.nuspec new file mode 100644 index 000000000..d0931142f --- /dev/null +++ b/nuspec/nuget/Cake.Issues.GitRepository.nuspec @@ -0,0 +1,45 @@ + + + + Cake.Issues.GitRepository + Cake.Issues.GitRepository + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Git repository linting support for the Cake.Issues addin for Cake Build Automation System + +The Git repository support for the Cake.Issues addin for Cake allows you to analyze Git repositories. + +This addin provides the aliases for analyzing Git repositories and create issues resulting from it using the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.GitRepository. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider code-analysis linting git + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + diff --git a/nuspec/nuget/Cake.Issues.InspectCode.nuspec b/nuspec/nuget/Cake.Issues.InspectCode.nuspec index 7345b9cee..876956121 100644 --- a/nuspec/nuget/Cake.Issues.InspectCode.nuspec +++ b/nuspec/nuget/Cake.Issues.InspectCode.nuspec @@ -16,6 +16,10 @@ It also requires the core Cake.Issues addin. There are also additional addins for generating reports or posting issues to pull requests. See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.InspectCode. MIT https://cakeissues.net @@ -24,7 +28,7 @@ See the Project Site for an overview of the whole ecosystem of addins for workin Copyright © Cake Issues contributors cake cake-addin cake-issues cake-issueprovider codeanalysis linting inspectcode - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.Markdownlint.nuspec b/nuspec/nuget/Cake.Issues.Markdownlint.nuspec index 13266bf08..a407a7f88 100644 --- a/nuspec/nuget/Cake.Issues.Markdownlint.nuspec +++ b/nuspec/nuget/Cake.Issues.Markdownlint.nuspec @@ -16,6 +16,10 @@ It also requires the core Cake.Issues addin. There are also additional addins for generating reports or posting issues to pull requests. See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.Markdownlint. MIT https://cakeissues.net @@ -24,7 +28,7 @@ See the Project Site for an overview of the whole ecosystem of addins for workin Copyright © Cake Issues contributors cake cake-addin cake-issues cake-issueprovider linting markdown markdownlint - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.MsBuild.nuspec b/nuspec/nuget/Cake.Issues.MsBuild.nuspec index 9a486493e..c78281d2d 100644 --- a/nuspec/nuget/Cake.Issues.MsBuild.nuspec +++ b/nuspec/nuget/Cake.Issues.MsBuild.nuspec @@ -28,7 +28,7 @@ For addin compatible with Cake Frosting see Cake.Frosting.Issues.MsBuild. Copyright © Cake Issues contributors cake cake-addin cake-issues cake-issueprovider code-analysis linting msbuild - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.PullRequests.AppVeyor.nuspec b/nuspec/nuget/Cake.Issues.PullRequests.AppVeyor.nuspec new file mode 100644 index 000000000..71ce82f97 --- /dev/null +++ b/nuspec/nuget/Cake.Issues.PullRequests.AppVeyor.nuspec @@ -0,0 +1,43 @@ + + + + Cake.Issues.PullRequests.AppVeyor + Cake.Issues.PullRequests.AppVeyor + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + AppVeyor support for the Cake.Issues addin for Cake Build Automation System + +AppVeyor support for the Cake.Issues addin for Cake allows you to write found issues as message to AppVeyor builds. + +This addin provides the aliases for writing to AppVeyor builds. +It also requires the core Cake.Issues and Cake.Issues.PullRequests addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.PullRequests.AppVeyor. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-pullrequestsystem issues pullrequest buildserver appveyor + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.PullRequests.AzureDevOps.nuspec b/nuspec/nuget/Cake.Issues.PullRequests.AzureDevOps.nuspec new file mode 100644 index 000000000..890508a1b --- /dev/null +++ b/nuspec/nuget/Cake.Issues.PullRequests.AzureDevOps.nuspec @@ -0,0 +1,44 @@ + + + + Cake.Issues.PullRequests.AzureDevOps + Cake.Issues.PullRequests.AzureDevOps + 0.0.0 + Cake Issues contributors + bbtsoftware, pascalberger, cake-contrib + Azure DevOps support for the Cake.Issues addin for Cake Build Automation System + +The Azure DevOps support for the Cake.Issues addin for Cake allows you to +write found issues as comments to Azure DevOps pull requests. + +This addin provides the aliases for writing to Azure DevOps pull requests. +It also requires the core Cake.Issues and Cake.Issues.PullRequests addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.PullRequests.AzureDevOps. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-pullrequestsystem issues pullrequest tfs azure-devops azure-devops-server + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.PullRequests.GitHubActions.nuspec b/nuspec/nuget/Cake.Issues.PullRequests.GitHubActions.nuspec new file mode 100644 index 000000000..00d88a090 --- /dev/null +++ b/nuspec/nuget/Cake.Issues.PullRequests.GitHubActions.nuspec @@ -0,0 +1,43 @@ + + + + Cake.Issues.PullRequests.GitHubActions + Cake.Issues.PullRequests.GitHubActions + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + GitHub Actions support for the Cake.Issues addin for Cake Build Automation System + +GitHub Actions support for the Cake.Issues addin for Cake allows you to report to GitHub Actions builds. + +This addin provides the aliases for writing to GitHub Actions builds. +It also requires the core Cake.Issues and Cake.Issues.PullRequests addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.PullRequests.GitHubActions. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-pullrequestsystem issues pullrequest buildserver github github-actions + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.PullRequests.nuspec b/nuspec/nuget/Cake.Issues.PullRequests.nuspec index 9cecac79a..e4b6e80b5 100644 --- a/nuspec/nuget/Cake.Issues.PullRequests.nuspec +++ b/nuspec/nuget/Cake.Issues.PullRequests.nuspec @@ -26,7 +26,7 @@ For addin compatible with Cake Frosting see Cake.Frosting.Issues.PullRequests. Copyright © Cake Issues contributors Cake Script Cake-Issues CodeAnalysis Linting Issues Pull-Requests - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.Reporting.Console.nuspec b/nuspec/nuget/Cake.Issues.Reporting.Console.nuspec new file mode 100644 index 000000000..1d1b0bb9b --- /dev/null +++ b/nuspec/nuget/Cake.Issues.Reporting.Console.nuspec @@ -0,0 +1,48 @@ + + + + Cake.Issues.Reporting.Console + Cake.Issues.Reporting.Console + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for reporting issues to console for the Cake.Issues addin for Cake Build Automation System + +This addin for the Cake.Issues addin for Cake Script Runners allows you to print issues to the console. + +This addin provides the aliases for reporting issues to the console. +It also requires the core Cake.Issues and Cake.Issues.Reporting addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.Reporting.Console. + +The addin requires Cake 1.2.0 or higher. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-reportformat issues reporting console + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.Reporting.Generic.nuspec b/nuspec/nuget/Cake.Issues.Reporting.Generic.nuspec new file mode 100644 index 000000000..2011f2d07 --- /dev/null +++ b/nuspec/nuget/Cake.Issues.Reporting.Generic.nuspec @@ -0,0 +1,36 @@ + + + + Cake.Issues.Reporting.Generic + Cake.Issues.Reporting.Generic + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for creating any reports in any text based format (HTML, Markdown, ...) for the Cake.Issues addin for Cake Build Automation System + +The generic report support for the Cake.Issues addin for Cake Script Runners allows you to create issue reports in any text format (HTML, Markdown, ...). + +This addin provides the aliases for any text based report format. +It also requires the core Cake.Issues and Cake.Issues.Reporting addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.Reporting.Generic. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-reportformat issues reporting html markdown razor + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.Reporting.Sarif.nuspec b/nuspec/nuget/Cake.Issues.Reporting.Sarif.nuspec new file mode 100644 index 000000000..138e5efb4 --- /dev/null +++ b/nuspec/nuget/Cake.Issues.Reporting.Sarif.nuspec @@ -0,0 +1,46 @@ + + + + Cake.Issues.Reporting.Sarif + Cake.Issues.Reporting.Sarif + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for creating SARIF compatible files for the Cake.Issues addin for Cake Build Automation System + +The SARIF support for the Cake.Issues addin for Cake allows you to create SARIF compatible files. + +This addin provides the aliases for creating SARIF compatible files. +It also requires the core Cake.Issues and Cake.Issues.Reporting addins and one or more issue providers. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.Reporting.Sarif. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-reportformat issues reporting sarif + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + diff --git a/nuspec/nuget/Cake.Issues.Reporting.nuspec b/nuspec/nuget/Cake.Issues.Reporting.nuspec index 6ca83a484..22211dea0 100644 --- a/nuspec/nuget/Cake.Issues.Reporting.nuspec +++ b/nuspec/nuget/Cake.Issues.Reporting.nuspec @@ -26,7 +26,7 @@ For addin compatible with Cake Frosting see Cake.Frosting.Issues.Reporting. Copyright © Cake Issues contributors Cake Script Cake-Issues CodeAnalysis Linting Issues Reporting - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.Sarif.nuspec b/nuspec/nuget/Cake.Issues.Sarif.nuspec new file mode 100644 index 000000000..ceb80d4f5 --- /dev/null +++ b/nuspec/nuget/Cake.Issues.Sarif.nuspec @@ -0,0 +1,48 @@ + + + + Cake.Issues.Sarif + Cake.Issues.Sarif + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Support for reading SARIF compatible files using the Cake.Issues addin for Cake Build Automation System + +The SARIF support for the Cake.Issues addin for Cake allows you to read SARIF compatible files. + +This addin provides the aliases for reading issues from SARIF compatible files and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.Sarif. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider linting sarif + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + + + + diff --git a/nuspec/nuget/Cake.Issues.Terraform.nuspec b/nuspec/nuget/Cake.Issues.Terraform.nuspec new file mode 100644 index 000000000..4c2ab84c0 --- /dev/null +++ b/nuspec/nuget/Cake.Issues.Terraform.nuspec @@ -0,0 +1,45 @@ + + + + Cake.Issues.Terraform + Cake.Issues.Terraform + 0.0.0 + Cake Issues contributors + pascalberger, cake-contrib + Terraform support for the Cake.Issues addin for Cake Build Automation System + +The Terraform support for the Cake.Issues addin for Cake allows you to read issues logged by terraform validate. + +This addin provides the aliases for reading terraform validate output and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + +NOTE: +This is the version of the addin compatible with Cake Script Runners. +For addin compatible with Cake Frosting see Cake.Frosting.Issues.Terraform. + + MIT + https://cakeissues.net + icon.png + false + + Copyright © Cake Issues contributors + cake cake-addin cake-issues cake-issueprovider linting terraform + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.Testing.nuspec b/nuspec/nuget/Cake.Issues.Testing.nuspec index 7d90931ed..ea6965026 100644 --- a/nuspec/nuget/Cake.Issues.Testing.nuspec +++ b/nuspec/nuget/Cake.Issues.Testing.nuspec @@ -17,7 +17,7 @@ Common helpers for testing add-ins based on Cake.Issues Copyright © Cake Issues contributors Cake Script Cake-Issues Issues Testing - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/nuspec/nuget/Cake.Issues.nuspec b/nuspec/nuget/Cake.Issues.nuspec index 0b60e865b..072dbd592 100644 --- a/nuspec/nuget/Cake.Issues.nuspec +++ b/nuspec/nuget/Cake.Issues.nuspec @@ -24,7 +24,7 @@ See the Project Site for an overview of the whole ecosystem of addins for workin Copyright © Cake Issues contributors cake cake-addin cake-issues code-analysis linting issues - https://github.com/cake-contrib/Cake.Issues/releases/tag/4.1.0 + https://github.com/cake-contrib/Cake.Issues/releases/tag/4.2.0 diff --git a/recipe.cake b/recipe.cake index 94225cf3d..4064a9e8c 100644 --- a/recipe.cake +++ b/recipe.cake @@ -14,11 +14,16 @@ BuildParameters.SetParameters( repositoryOwner: "cake-contrib", repositoryName: "Cake.Issues", appVeyorAccountName: "cakecontrib", + shouldGenerateDocumentation: false, // Documentation is generated from Cake.Issues.Website shouldRunCoveralls: false, // Disabled because it's currently failing shouldPostToGitter: false); // Disabled because it's currently failing BuildParameters.PrintParameters(Context); +ToolSettings.SetToolPreprocessorDirectives( + gitReleaseManagerGlobalTool: "#tool dotnet:?package=GitReleaseManager.Tool&version=0.17.0" +); + ToolSettings.SetToolSettings( context: Context, testCoverageFilter: "+[*]* -[xunit.*]* -[Cake.Core]* -[Cake.Testing]* -[*.Tests]* -[Cake.Issues]LitJson.* -[Shouldly]* -[DiffEngine]* -[EmptyFiles]*", diff --git a/src/Cake.Issues.DocFx.Tests/Cake.Issues.DocFx.Tests.csproj b/src/Cake.Issues.DocFx.Tests/Cake.Issues.DocFx.Tests.csproj index 020f81659..750ddbe76 100644 --- a/src/Cake.Issues.DocFx.Tests/Cake.Issues.DocFx.Tests.csproj +++ b/src/Cake.Issues.DocFx.Tests/Cake.Issues.DocFx.Tests.csproj @@ -39,10 +39,10 @@ all - 2.7.0 + 2.7.1 - 2.5.7 + 2.5.8 runtime; build; native; contentfiles; analyzers all diff --git a/src/Cake.Issues.EsLint.Tests/Cake.Issues.EsLint.Tests.csproj b/src/Cake.Issues.EsLint.Tests/Cake.Issues.EsLint.Tests.csproj index 329ef81c4..41d3960d9 100644 --- a/src/Cake.Issues.EsLint.Tests/Cake.Issues.EsLint.Tests.csproj +++ b/src/Cake.Issues.EsLint.Tests/Cake.Issues.EsLint.Tests.csproj @@ -33,8 +33,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/Cake.Issues.EsLint/BaseEsLintLogFileFormat.cs b/src/Cake.Issues.EsLint/BaseEsLintLogFileFormat.cs index c13456291..30207b994 100644 --- a/src/Cake.Issues.EsLint/BaseEsLintLogFileFormat.cs +++ b/src/Cake.Issues.EsLint/BaseEsLintLogFileFormat.cs @@ -5,15 +5,9 @@ /// /// Base class for all ESLint log file format implementations. /// - public abstract class BaseEsLintLogFileFormat : BaseLogFileFormat + /// The Cake log instance. + public abstract class BaseEsLintLogFileFormat(ICakeLog log) + : BaseLogFileFormat(log) { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log instance. - protected BaseEsLintLogFileFormat(ICakeLog log) - : base(log) - { - } } } diff --git a/src/Cake.Issues.GitRepository.Tests/Cake.Issues.GitRepository.Tests.csproj b/src/Cake.Issues.GitRepository.Tests/Cake.Issues.GitRepository.Tests.csproj new file mode 100644 index 000000000..d3b246899 --- /dev/null +++ b/src/Cake.Issues.GitRepository.Tests/Cake.Issues.GitRepository.Tests.csproj @@ -0,0 +1,49 @@ + + + + Library + net6.0 + false + Tests for the Cake.Issues.GitRepository addin + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + ..\Cake.Issues.Tests.ruleset + + + ..\Cake.Issues.Tests.ruleset + + + + + + + 4.0.0 + + + 4.2.1 + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + 2.7.1 + + + 2.5.8 + runtime; build; native; contentfiles; analyzers + all + + + + + + + + + diff --git a/src/Cake.Issues.GitRepository.Tests/GitRunnerFixture.cs b/src/Cake.Issues.GitRepository.Tests/GitRunnerFixture.cs new file mode 100644 index 000000000..2c83ac9c2 --- /dev/null +++ b/src/Cake.Issues.GitRepository.Tests/GitRunnerFixture.cs @@ -0,0 +1,31 @@ +namespace Cake.Issues.GitRepository.Tests +{ + using System.Collections.Generic; + using Cake.Testing.Fixtures; + + internal class GitRunnerFixture : ToolFixture + { + private readonly List standardOutput = []; + + public GitRunnerFixture() + : base("git") + { + } + + public IEnumerable StandardOutput => this.standardOutput; + + protected override void RunTool() + { + this.standardOutput.Clear(); + + var tool = new GitRunner(this.FileSystem, this.Environment, this.ProcessRunner, this.Tools); + + var output = tool.RunCommand(this.Settings); + + if (output != null) + { + this.standardOutput.AddRange(output); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.GitRepository.Tests/GitRunnerTests.cs b/src/Cake.Issues.GitRepository.Tests/GitRunnerTests.cs new file mode 100644 index 000000000..609c277e7 --- /dev/null +++ b/src/Cake.Issues.GitRepository.Tests/GitRunnerTests.cs @@ -0,0 +1,39 @@ +namespace Cake.Issues.GitRepository.Tests +{ + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class GitRunnerTests + { + public sealed class TheRunCommandMethod + { + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var fixture = new GitRunnerFixture + { + Settings = null, + }; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + result.IsArgumentNullException("settings"); + } + + [Fact] + public void Arguments_Should_Be_Added_If_Settings_Are_Passed() + { + var fixture = new GitRunnerFixture(); + fixture.Settings.Arguments.Add("Bar"); + + var result = fixture.Run(); + + result.Args.ShouldBe("Bar"); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.GitRepository.Tests/IssueBuilderExtensionsTests.cs b/src/Cake.Issues.GitRepository.Tests/IssueBuilderExtensionsTests.cs new file mode 100644 index 000000000..c334ac0fc --- /dev/null +++ b/src/Cake.Issues.GitRepository.Tests/IssueBuilderExtensionsTests.cs @@ -0,0 +1,110 @@ +namespace Cake.Issues.GitRepository.Tests +{ + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class IssueBuilderExtensionsTests + { + public sealed class TheOfRuleMethod + { + [Fact] + public void Should_Throw_If_IssueBuilder_Is_Null() + { + // Given + IssueBuilder issueBuilder = null; + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + // When + var result = Record.Exception(() => issueBuilder.OfRule(ruleDescription)); + + // Then + result.IsArgumentNullException("issueBuilder"); + } + + [Fact] + public void Should_Throw_If_RuleDescription_Is_Null() + { + // Given + var issueBuilder = IssueBuilder.NewIssue("message", "providerType", "providerName"); + BaseGitRepositoryIssuesRuleDescription ruleDescription = null; + + // When + var result = Record.Exception(() => issueBuilder.OfRule(ruleDescription)); + + // Then + result.IsArgumentNullException("ruleDescription"); + } + + [Fact] + public void Should_Set_RuleId() + { + // Given + var issueBuilder = IssueBuilder.NewIssue("message", "providerType", "providerName"); + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + // When + var result = issueBuilder.OfRule(ruleDescription); + + // Then + result.Create().RuleId.ShouldBe(ruleDescription.RuleId); + } + + [Fact] + public void Should_Set_RuleName() + { + // Given + var issueBuilder = IssueBuilder.NewIssue("message", "providerType", "providerName"); + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + // When + var result = issueBuilder.OfRule(ruleDescription); + + // Then + result.Create().RuleName.ShouldBe(ruleDescription.RuleName); + } + + [Fact] + public void Should_Set_RuleUrl() + { + // Given + var issueBuilder = IssueBuilder.NewIssue("message", "providerType", "providerName"); + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + // When + var result = issueBuilder.OfRule(ruleDescription); + + // Then + result.Create().RuleUrl.ToString().ShouldBe("https://cakeissues.net/docs/issue-providers/gitrepository/rules/BinaryFileNotTrackedByLfs"); + } + + [Fact] + public void Should_Set_Priority() + { + // Given + var issueBuilder = IssueBuilder.NewIssue("message", "providerType", "providerName"); + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + // When + var result = issueBuilder.OfRule(ruleDescription); + + // Then + result.Create().Priority.ShouldBe((int)ruleDescription.Priority); + } + + [Fact] + public void Should_Set_PriorityName() + { + // Given + var issueBuilder = IssueBuilder.NewIssue("message", "providerType", "providerName"); + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + // When + var result = issueBuilder.OfRule(ruleDescription); + + // Then + result.Create().PriorityName.ShouldBe(ruleDescription.Priority.ToString()); + } + } + } +} diff --git a/src/Cake.Issues.GitRepository.Tests/Properties/ProjectInfo.cs b/src/Cake.Issues.GitRepository.Tests/Properties/ProjectInfo.cs new file mode 100644 index 000000000..3a33d3fb7 --- /dev/null +++ b/src/Cake.Issues.GitRepository.Tests/Properties/ProjectInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1634d785-eac1-4e1c-ba92-439508463b8f")] diff --git a/src/Cake.Issues.GitRepository/BaseGitRepositoryIssuesRuleDescription.cs b/src/Cake.Issues.GitRepository/BaseGitRepositoryIssuesRuleDescription.cs new file mode 100644 index 000000000..cca1e9349 --- /dev/null +++ b/src/Cake.Issues.GitRepository/BaseGitRepositoryIssuesRuleDescription.cs @@ -0,0 +1,23 @@ +namespace Cake.Issues.GitRepository +{ + /// + /// Base class for descriptions of rules checked by . + /// + public abstract class BaseGitRepositoryIssuesRuleDescription + { + /// + /// Gets the ID of the rule. + /// + public abstract string RuleId { get; } + + /// + /// Gets the name of the rule. + /// + public abstract string RuleName { get; } + + /// + /// Gets the priority of the rule. + /// + public abstract IssuePriority Priority { get; } + } +} diff --git a/src/Cake.Issues.GitRepository/BinaryFileNotTrackedByLfsRuleDescription.cs b/src/Cake.Issues.GitRepository/BinaryFileNotTrackedByLfsRuleDescription.cs new file mode 100644 index 000000000..734cb679b --- /dev/null +++ b/src/Cake.Issues.GitRepository/BinaryFileNotTrackedByLfsRuleDescription.cs @@ -0,0 +1,17 @@ +namespace Cake.Issues.GitRepository +{ + /// + /// Description of the rule which checks if a binary file in the repository is tracked by Git Large File System. + /// + public class BinaryFileNotTrackedByLfsRuleDescription : BaseGitRepositoryIssuesRuleDescription + { + /// + public override string RuleId => "BinaryFileNotTrackedByLfs"; + + /// + public override string RuleName => "Binary file not tracked by Git LFS"; + + /// + public override IssuePriority Priority => IssuePriority.Warning; + } +} diff --git a/src/Cake.Issues.GitRepository/Cake.Issues.GitRepository.csproj b/src/Cake.Issues.GitRepository/Cake.Issues.GitRepository.csproj new file mode 100644 index 000000000..c2fcd86d9 --- /dev/null +++ b/src/Cake.Issues.GitRepository/Cake.Issues.GitRepository.csproj @@ -0,0 +1,47 @@ + + + + Library + net6.0;net7.0;net8.0 + Git repository linting support for the Cake.Issues addin for Cake Build Automation System + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + + + + bin\Debug\Cake.Issues.GitRepository.xml + DEBUG;TRACE + + + + bin\Release\Cake.Issues.GitRepository.xml + TRACE + + + + + 4.0.0 + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + + + + diff --git a/src/Cake.Issues.GitRepository/FilePathTooLongRuleDescription.cs b/src/Cake.Issues.GitRepository/FilePathTooLongRuleDescription.cs new file mode 100644 index 000000000..1b51ebed6 --- /dev/null +++ b/src/Cake.Issues.GitRepository/FilePathTooLongRuleDescription.cs @@ -0,0 +1,17 @@ +namespace Cake.Issues.GitRepository +{ + /// + /// Description of the rule which checks if the path of a file in the repository is too long. + /// + public class FilePathTooLongRuleDescription : BaseGitRepositoryIssuesRuleDescription + { + /// + public override string RuleId => "FilePathTooLong"; + + /// + public override string RuleName => "File path too long"; + + /// + public override IssuePriority Priority => IssuePriority.Warning; + } +} diff --git a/src/Cake.Issues.GitRepository/GitRepositoryIssuesAliases.cs b/src/Cake.Issues.GitRepository/GitRepositoryIssuesAliases.cs new file mode 100644 index 000000000..01dedb41b --- /dev/null +++ b/src/Cake.Issues.GitRepository/GitRepositoryIssuesAliases.cs @@ -0,0 +1,70 @@ +namespace Cake.Issues.GitRepository +{ + using Cake.Core; + using Cake.Core.Annotations; + + /// + /// Contains functionality related to analyze Git repositories. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class GitRepositoryIssuesAliases + { + /// + /// Gets the name of the Git repository issue provider. + /// This name can be used to identify issues based on the property. + /// + /// The context. + /// Name of the Git repository issue provider. + [CakePropertyAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static string GitRepositoryIssuesProviderTypeName( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return GitRepositoryIssuesProvider.ProviderTypeName; + } + + /// + /// Gets an instance of a provider for analyzing a Git repository and reporting issues using specified settings. + /// + /// The context. + /// Settings for analyzing the Git repository. + /// Instance of a provider for analyzing a Git repository and reporting issues. + /// + /// Check for binary files not tracked by Git LFS: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider GitRepositoryIssues( + this ICakeContext context, + GitRepositoryIssuesSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return + new GitRepositoryIssuesProvider( + context.Log, + context.FileSystem, + context.Environment, + context.ProcessRunner, + context.Tools, + settings); + } + } +} diff --git a/src/Cake.Issues.GitRepository/GitRepositoryIssuesProvider.cs b/src/Cake.Issues.GitRepository/GitRepositoryIssuesProvider.cs new file mode 100644 index 000000000..81125e494 --- /dev/null +++ b/src/Cake.Issues.GitRepository/GitRepositoryIssuesProvider.cs @@ -0,0 +1,295 @@ +namespace Cake.Issues.GitRepository +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Cake.Core; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Cake.Core.Tooling; + + /// + /// Provider for issues in Git repositories. + /// + internal class GitRepositoryIssuesProvider : BaseIssueProvider + { + private readonly GitRunner runner; + private readonly Lazy> allFiles; + private readonly Lazy> textFiles; + private readonly Lazy> binaryFiles; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake log context. + /// The file system. + /// The Cake environment. + /// The process runner. + /// The tool locator. + /// Settings for the issue provider. + public GitRepositoryIssuesProvider( + ICakeLog log, + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator toolLocator, + GitRepositoryIssuesSettings issueProviderSettings) + : base(log) + { + fileSystem.NotNull(nameof(fileSystem)); + environment.NotNull(nameof(environment)); + processRunner.NotNull(nameof(processRunner)); + toolLocator.NotNull(nameof(toolLocator)); + issueProviderSettings.NotNull(nameof(issueProviderSettings)); + + this.IssueProviderSettings = issueProviderSettings; + this.runner = new GitRunner(fileSystem, environment, processRunner, toolLocator); + + this.allFiles = + new Lazy>( + new Func>( + () => this.GetAllFilesFromRepository())); + this.textFiles = + new Lazy>( + new Func>( + () => this.GetTextFilesFromRepository())); + this.binaryFiles = + new Lazy>( + new Func>( + () => this.DetermineBinaryFiles(this.allFiles.Value, this.textFiles.Value))); + } + + /// + /// Gets the name of the Git repository issue provider. + /// This name can be used to identify issues based on the property. + /// + public static string ProviderTypeName => typeof(GitRepositoryIssuesProvider).FullName; + + /// + public override string ProviderName => "Git Repository"; + + /// + /// Gets the settings for the issue provider. + /// + protected GitRepositoryIssuesSettings IssueProviderSettings { get; private set; } + + /// + protected override IEnumerable InternalReadIssues() + { + var result = new List(); + + if (this.IssueProviderSettings.CheckBinaryFilesTrackedByLfs) + { + result.AddRange(this.CheckForBinaryFilesNotTrackedByLfs()); + } + + if (this.IssueProviderSettings.CheckFilesPathLength) + { + result.AddRange(this.CheckForFilesPathLength()); + } + + return result; + } + + /// + /// Checks for binary files which are not tracked by LFS. + /// + /// List of issues for binary files which are not tracked by LFS. + private List CheckForBinaryFilesNotTrackedByLfs() + { + if (!this.allFiles.Value.Any()) + { + return []; + } + + if (!this.binaryFiles.Value.Any()) + { + return []; + } + + var lfsTrackedFiles = this.GetLfsTrackedFilesFromRepository(); + var binaryFilesNotTrackedByLfs = + this.DetermineBinaryFilesNotTrackedWithLfs(this.binaryFiles.Value, lfsTrackedFiles); + + var result = new List(); + foreach (var file in binaryFilesNotTrackedByLfs) + { + var ruleDescription = new BinaryFileNotTrackedByLfsRuleDescription(); + + result.Add( + IssueBuilder + .NewIssue($"The binary file \"{file}\" is not tracked by Git LFS", this) + .WithMessageInHtmlFormat($"The binary file {file} is not tracked by Git LFS") + .WithMessageInMarkdownFormat($"The binary file `{file}` is not tracked by Git LFS") + .InFile(file) + .OfRule(ruleDescription) + .Create()); + } + + return result; + } + + /// + /// Checks for files path length. + /// + /// List of issues for repository files with paths exceeding the allowed maximum. + private List CheckForFilesPathLength() + { + if (!this.allFiles.Value.Any()) + { + return []; + } + + var result = new List(); + foreach (string file in this.allFiles.Value) + { + if (file.Length > this.IssueProviderSettings.MaxFilePathLength) + { + var ruleDescription = new FilePathTooLongRuleDescription(); + + result.Add( + IssueBuilder + .NewIssue($"The path for the file \"{file}\" is too long. Maximum allowed path length is {this.IssueProviderSettings.MaxFilePathLength}, actual path length is {file.Length}.", this) + .WithMessageInHtmlFormat($"The path for the file {file} is too long. Maximum allowed path length is {this.IssueProviderSettings.MaxFilePathLength}, actual path length is {file.Length}.") + .WithMessageInMarkdownFormat($"The path for the file `{file}` is too long. Maximum allowed path length is {this.IssueProviderSettings.MaxFilePathLength}, actual path length is {file.Length}.") + .InFile(file) + .OfRule(ruleDescription) + .Create()); + } + } + + return result; + } + + /// + /// Returns a list of the files in the repository. + /// + /// List of files in the repository. + private List GetAllFilesFromRepository() + { + this.Log.Verbose("Reading all files from repository '{0}'...", this.Settings.RepositoryRoot); + + var settings = new GitRunnerSettings + { + WorkingDirectory = this.Settings.RepositoryRoot, + }; + + settings.Arguments.Clear(); + settings.Arguments.Add("ls-files -z"); + var allFiles = + string.Join( + string.Empty, + this.runner.RunCommand(settings)) + .Split('\0') + .Where(x => !string.IsNullOrEmpty(x)) + .ToList() + ?? throw new Exception("Error reading files from repository"); + this.Log.Verbose("Found {0} file(s)", allFiles.Count); + + return allFiles; + } + + /// + /// Returns a list of text files in the repository. + /// + /// List of text files in the repository. + private List GetTextFilesFromRepository() + { + this.Log.Verbose("Reading all text files from repository '{0}'...", this.Settings.RepositoryRoot); + + var settings = new GitRunnerSettings + { + WorkingDirectory = this.Settings.RepositoryRoot, + + // git grep -IL . can return an exit code of 1 if nothing matches + HandleExitCode = exitCode => (exitCode == 0 || exitCode == 1), + }; + + settings.Arguments.Clear(); + settings.Arguments.Add("grep -Il ."); + var textFiles = + this.runner.RunCommand(settings) + ?? throw new Exception("Error reading text files from repository"); + settings.Arguments.Clear(); + settings.Arguments.Add("grep -IL ."); + var emptyFiles = this.runner.RunCommand(settings); + if (emptyFiles != null && emptyFiles.Any()) + { + textFiles = textFiles.Concat(emptyFiles); + } + + var result = textFiles.ToList(); + + this.Log.Verbose("Found {0} text file(s)", result.Count); + + return result; + } + + /// + /// Returns a list of files tracked by Git LFS. + /// + /// List of files tracked by Git LFS. + private IEnumerable GetLfsTrackedFilesFromRepository() + { + this.Log.Verbose("Reading all LFS tracked files from repository '{0}'...", this.Settings.RepositoryRoot); + + var settings = new GitRunnerSettings + { + WorkingDirectory = this.Settings.RepositoryRoot, + }; + + settings.Arguments.Clear(); + settings.Arguments.Add("lfs ls-files -n"); + var lfsTrackedFiles = + this.runner.RunCommand(settings) + ?? throw new Exception("Error reading LFS tracked files from repository"); + this.Log.Verbose("Found {0} LFS tracked file(s)", lfsTrackedFiles.Count()); + + return lfsTrackedFiles; + } + + /// + /// Determines binary files. + /// + /// List of all files in the repository. + /// List of text files in the repository. + /// List of binary files in the repository. + private List DetermineBinaryFiles(IEnumerable allFiles, IEnumerable textFiles) + { + this.Log.Verbose("Determine binary files..."); + + var binaryFiles = allFiles.Except(textFiles).ToList(); + + if (binaryFiles.Count > 0) + { + this.Log.Debug(string.Join(Environment.NewLine, binaryFiles)); + } + + this.Log.Verbose("Found {0} binary file(s)", binaryFiles.Count); + + return binaryFiles; + } + + /// + /// Determines binary files which are not tracked with LFS. + /// + /// List of binary files in the repository. + /// List of files tracked with LFS in the repository. + /// List of binary files in the repository which are not tracked with LFS. + private List DetermineBinaryFilesNotTrackedWithLfs(IEnumerable binaryFiles, IEnumerable lfsTrackedFiles) + { + this.Log.Verbose("Checking if binary files are tracked by LFS..."); + + var binaryFilesNotTrackedWithLfs = binaryFiles.Except(lfsTrackedFiles).ToList(); + + if (binaryFilesNotTrackedWithLfs.Count > 0) + { + this.Log.Debug(string.Join(Environment.NewLine, binaryFilesNotTrackedWithLfs)); + } + + this.Log.Verbose("Found {0} binary file(s) not tracked by LFS", binaryFilesNotTrackedWithLfs.Count); + + return binaryFilesNotTrackedWithLfs; + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.GitRepository/GitRepositoryIssuesSettings.cs b/src/Cake.Issues.GitRepository/GitRepositoryIssuesSettings.cs new file mode 100644 index 000000000..661246cdd --- /dev/null +++ b/src/Cake.Issues.GitRepository/GitRepositoryIssuesSettings.cs @@ -0,0 +1,27 @@ +namespace Cake.Issues.GitRepository +{ + /// + /// Settings for . + /// + public class GitRepositoryIssuesSettings + { + /// + /// Gets or sets a value indicating whether the repository should be checked for + /// binary files not tracked by Git LFS. + /// Requires Git and Git-LFS to be available through Cake tool resolution. + /// + public bool CheckBinaryFilesTrackedByLfs { get; set; } + + /// + /// Gets or sets a value indicating whether the repository should be checked for + /// files path longer than . + /// + public bool CheckFilesPathLength { get; set; } + + /// + /// Gets or sets a value indicating the maximum allowed length of file paths if + /// is enabled. + /// + public int MaxFilePathLength { get; set; } + } +} diff --git a/src/Cake.Issues.GitRepository/GitRunner.cs b/src/Cake.Issues.GitRepository/GitRunner.cs new file mode 100644 index 000000000..a8dbe893e --- /dev/null +++ b/src/Cake.Issues.GitRepository/GitRunner.cs @@ -0,0 +1,84 @@ +namespace Cake.Issues.GitRepository +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using Cake.Core; + using Cake.Core.IO; + using Cake.Core.Tooling; + + /// + /// A wrapper around the Git CLI. + /// + /// The file system. + /// The Cake environment. + /// The process runner. + /// The tool locator. + internal class GitRunner( + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator toolLocator) + : Tool(fileSystem, environment, processRunner, toolLocator) + { + /// + /// Runs Git with specified settings. + /// + /// Settings for running Git. + /// Output of command. + public IEnumerable RunCommand(GitRunnerSettings settings) + { + ArgumentNullException.ThrowIfNull(settings); + + var args = new ProcessArgumentBuilder(); + settings.Evaluate(args); + + var processSettings = new ProcessSettings + { + WorkingDirectory = settings.WorkingDirectory, + Arguments = args.Render(), + RedirectStandardOutput = true, + }; + + var currentEncoding = Console.OutputEncoding; + Console.OutputEncoding = Encoding.UTF8; + try + { + IEnumerable result = null; + this.Run( + settings, + null, + processSettings, + process => + { + result = process.GetStandardOutput(); + }); + return result?.ToList(); + } + finally + { + Console.OutputEncoding = currentEncoding; + } + } + + /// + /// Gets the name of the tool. + /// + /// The name of the tool. + protected override string GetToolName() + { + return "Git"; + } + + /// + /// Gets the names of the tool executables. + /// + /// The tool executable names. + protected override IEnumerable GetToolExecutableNames() + { + yield return "git.exe"; + yield return "git"; + } + } +} diff --git a/src/Cake.Issues.GitRepository/GitRunnerSettings.cs b/src/Cake.Issues.GitRepository/GitRunnerSettings.cs new file mode 100644 index 000000000..bc190f511 --- /dev/null +++ b/src/Cake.Issues.GitRepository/GitRunnerSettings.cs @@ -0,0 +1,32 @@ +namespace Cake.Issues.GitRepository +{ + using System.Collections.Generic; + using Cake.Core; + using Cake.Core.IO; + using Cake.Core.Tooling; + + /// + /// Settings for . + /// + internal class GitRunnerSettings : ToolSettings + { + private readonly List arguments = []; + + /// + /// Gets arguments to pass to the target script. + /// + public IList Arguments => this.arguments; + + /// + /// Evaluates the settings and writes them into . + /// + /// Argument builder to which the settings should be added. + internal void Evaluate(ProcessArgumentBuilder args) + { + foreach (var arg in this.Arguments) + { + args.Append(arg); + } + } + } +} diff --git a/src/Cake.Issues.GitRepository/IssueBuilderExtensions.cs b/src/Cake.Issues.GitRepository/IssueBuilderExtensions.cs new file mode 100644 index 000000000..d186da664 --- /dev/null +++ b/src/Cake.Issues.GitRepository/IssueBuilderExtensions.cs @@ -0,0 +1,30 @@ +namespace Cake.Issues.GitRepository +{ + using System; + + /// + /// Extensions for . + /// + internal static class IssueBuilderExtensions + { + /// + /// Sets the rule and priority of the issue. + /// + /// Issue builder on which the properties should be set. + /// Rule metadata. + /// Issue Builder instance. + public static IssueBuilder OfRule(this IssueBuilder issueBuilder, BaseGitRepositoryIssuesRuleDescription ruleDescription) + { + issueBuilder.NotNull(nameof(issueBuilder)); + ruleDescription.NotNull(nameof(ruleDescription)); + + return + issueBuilder + .OfRule( + ruleDescription.RuleId, + ruleDescription.RuleName, + new Uri($"https://cakeissues.net/docs/issue-providers/gitrepository/rules/{ruleDescription.RuleId}")) + .WithPriority(ruleDescription.Priority); + } + } +} diff --git a/src/Cake.Issues.GitRepository/Properties/ProjectInfo.cs b/src/Cake.Issues.GitRepository/Properties/ProjectInfo.cs new file mode 100644 index 000000000..141b5b4e6 --- /dev/null +++ b/src/Cake.Issues.GitRepository/Properties/ProjectInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("59cb34ad-3089-483c-8006-3f6aa54ed9d3")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.GitRepository.Tests")] diff --git a/src/Cake.Issues.InspectCode.Tests/Cake.Issues.InspectCode.Tests.csproj b/src/Cake.Issues.InspectCode.Tests/Cake.Issues.InspectCode.Tests.csproj index 0c629b8a0..450f2420b 100644 --- a/src/Cake.Issues.InspectCode.Tests/Cake.Issues.InspectCode.Tests.csproj +++ b/src/Cake.Issues.InspectCode.Tests/Cake.Issues.InspectCode.Tests.csproj @@ -32,9 +32,9 @@ all runtime; build; native; contentfiles; analyzers - + - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Cake.Issues.Markdownlint.Tests/Cake.Issues.Markdownlint.Tests.csproj b/src/Cake.Issues.Markdownlint.Tests/Cake.Issues.Markdownlint.Tests.csproj index 4b68bf4bd..a6e66b817 100644 --- a/src/Cake.Issues.Markdownlint.Tests/Cake.Issues.Markdownlint.Tests.csproj +++ b/src/Cake.Issues.Markdownlint.Tests/Cake.Issues.Markdownlint.Tests.csproj @@ -62,10 +62,10 @@ - 2.7.0 + 2.7.1 - 2.5.7 + 2.5.8 runtime; build; native; contentfiles; analyzers all diff --git a/src/Cake.Issues.Markdownlint/BaseMarkdownlintLogFileFormat.cs b/src/Cake.Issues.Markdownlint/BaseMarkdownlintLogFileFormat.cs index 8af30d86d..3ae670837 100644 --- a/src/Cake.Issues.Markdownlint/BaseMarkdownlintLogFileFormat.cs +++ b/src/Cake.Issues.Markdownlint/BaseMarkdownlintLogFileFormat.cs @@ -5,15 +5,9 @@ /// /// Base class for all log file formats supported by the Markdownlint issue provider. /// - public abstract class BaseMarkdownlintLogFileFormat : BaseLogFileFormat + /// The Cake log instance. + public abstract class BaseMarkdownlintLogFileFormat(ICakeLog log) + : BaseLogFileFormat(log) { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log instance. - protected BaseMarkdownlintLogFileFormat(ICakeLog log) - : base(log) - { - } } } diff --git a/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj b/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj index dcb026421..08b0375ce 100644 --- a/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj +++ b/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj @@ -31,8 +31,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs b/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs index 4fda4c1ff..5cf8a90c8 100644 --- a/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs +++ b/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs @@ -5,17 +5,10 @@ /// /// Base class for all MSBuild log file format. /// - public abstract class BaseMsBuildLogFileFormat : BaseLogFileFormat + /// The Cake log instance. + public abstract class BaseMsBuildLogFileFormat(ICakeLog log) + : BaseLogFileFormat(log) { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log instance. - protected BaseMsBuildLogFileFormat(ICakeLog log) - : base(log) - { - } - /// /// Validates a file path. /// diff --git a/src/Cake.Issues.PullRequests.AppVeyor.Tests/AppVeyorBuildSettingsTests.cs b/src/Cake.Issues.PullRequests.AppVeyor.Tests/AppVeyorBuildSettingsTests.cs new file mode 100644 index 000000000..303298b6c --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor.Tests/AppVeyorBuildSettingsTests.cs @@ -0,0 +1,74 @@ +namespace Cake.Issues.PullRequests.AppVeyor.Tests +{ + using System; + using Cake.Issues.Testing; + using Cake.Testing; + using Shouldly; + using Xunit; + + public sealed class AppVeyorBuildSettingsTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_MessagePattern_Is_Null() + { + // Given + string messagePattern = null; + var settings = new AppVeyorBuildSettings(); + + // When + var result = Record.Exception(() => settings.MessagePattern = messagePattern); + + // Then + result.IsArgumentNullException("value"); + } + + [Fact] + public void Should_Throw_If_DetailsPattern_Is_Null() + { + // Given + string detailsPattern = null; + var settings = new AppVeyorBuildSettings(); + + // When + var result = Record.Exception(() => settings.DetailsPattern = detailsPattern); + + // Then + result.IsArgumentNullException("value"); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData("foo")] + public void Should_Set_MessagePattern(string messagePattern) + { + // Given + var settings = new AppVeyorBuildSettings(); + + // When + settings.MessagePattern = messagePattern; + + // Then + settings.MessagePattern.ShouldBe(messagePattern); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData("foo")] + public void Should_Set_DetailsPattern(string detailsPattern) + { + // Given + var settings = new AppVeyorBuildSettings(); + + // When + settings.DetailsPattern = detailsPattern; + + // Then + settings.DetailsPattern.ShouldBe(detailsPattern); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.AppVeyor.Tests/Cake.Issues.PullRequests.AppVeyor.Tests.csproj b/src/Cake.Issues.PullRequests.AppVeyor.Tests/Cake.Issues.PullRequests.AppVeyor.Tests.csproj new file mode 100644 index 000000000..3705cf178 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor.Tests/Cake.Issues.PullRequests.AppVeyor.Tests.csproj @@ -0,0 +1,35 @@ + + + + net6.0 + false + Cake.Issues + Tests for the Cake.Issues.PullRequests.AppVeyor addin + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildSettings.cs b/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildSettings.cs new file mode 100644 index 000000000..76efd1486 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildSettings.cs @@ -0,0 +1,48 @@ +namespace Cake.Issues.PullRequests.AppVeyor +{ + /// + /// Settings for . + /// + public class AppVeyorBuildSettings + { + private string messagePattern = "Project: {ProjectName}, File: {FilePath}, Line: {Line}"; + private string detailsPattern = "{Rule}: {MessageText}"; + + /// + /// Initializes a new instance of the class. + /// + public AppVeyorBuildSettings() + { + } + + /// + /// Gets or sets the pattern of the message to display. + /// See for possible patterns. + /// The default value is: "Project: {ProjectName}, File: {FilePath}, Line: {Line}". + /// + public string MessagePattern + { + get => this.messagePattern; + set + { + value.NotNull(nameof(value)); + this.messagePattern = value; + } + } + + /// + /// Gets or sets the pattern of the message details to display. + /// See for possible patterns. + /// The default value is: "{Rule}: {MessageText}". + /// + public string DetailsPattern + { + get => this.detailsPattern; + set + { + value.NotNull(nameof(value)); + this.detailsPattern = value; + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildsAliases.cs b/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildsAliases.cs new file mode 100644 index 000000000..ecd20dc0a --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorBuildsAliases.cs @@ -0,0 +1,77 @@ +namespace Cake.Issues.PullRequests.AppVeyor +{ + using Cake.Core; + using Cake.Core.Annotations; + + /// + /// Contains functionality related to writing code analysis issues to AppVeyor builds. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class AppVeyorBuildsAliases + { + /// + /// Gets an object for writing issues to AppVeyor builds using the default settings. + /// + /// The context. + /// Object for writing issues to AppVeyor builds. + /// + /// Report code analysis issues reported as MsBuild warnings to an AppVeyor build: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AppVeyorBuilds( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return new AppVeyorPullRequestSystem(context, new AppVeyorBuildSettings()); + } + + /// + /// Gets an object for writing issues to AppVeyor builds using the specified settings. + /// + /// The context. + /// Settings for accessing AppVeyor. + /// Object for writing issues to AppVeyor builds. + /// + /// Report code analysis issues reported as MsBuild warnings to an AppVeyor build: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AppVeyorBuilds( + this ICakeContext context, + AppVeyorBuildSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new AppVeyorPullRequestSystem(context, settings); + } + } +} diff --git a/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorPullRequestSystem.cs b/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorPullRequestSystem.cs new file mode 100644 index 000000000..ba61418a6 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor/AppVeyorPullRequestSystem.cs @@ -0,0 +1,41 @@ +namespace Cake.Issues.PullRequests.AppVeyor +{ + using System.Collections.Generic; + using Cake.Common.Build; + using Cake.Core; + + /// + /// Class for posting issues to AppVeyor. + /// + public class AppVeyorPullRequestSystem : BasePullRequestSystem + { + private readonly ICakeContext context; + private readonly AppVeyorBuildSettings settings; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake context. + /// Settings for writting issues to AppVeyor. + public AppVeyorPullRequestSystem(ICakeContext context, AppVeyorBuildSettings settings) + : base(context?.Log) + { + settings.NotNull(nameof(settings)); + + this.context = context; + this.settings = settings; + } + + /// + protected override void InternalPostDiscussionThreads(IEnumerable issues, string commentSource) + { + foreach (var issue in issues) + { + this.context.AppVeyor().AddMessage( + this.settings.MessagePattern.ReplaceIssuePattern(issue), + issue.Priority.ToAppVeyorMessageCategoryType(), + this.settings.DetailsPattern.ReplaceIssuePattern(issue)); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AppVeyor/Cake.Issues.PullRequests.AppVeyor.csproj b/src/Cake.Issues.PullRequests.AppVeyor/Cake.Issues.PullRequests.AppVeyor.csproj new file mode 100644 index 000000000..a88329ed7 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor/Cake.Issues.PullRequests.AppVeyor.csproj @@ -0,0 +1,36 @@ + + + + net6.0;net7.0;net8.0 + Addin for writing code analyzer or linter issues to AppVeyor + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + bin\$(Configuration)\$(TargetFramework)\Cake.Issues.PullRequests.AppVeyor.xml + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.AppVeyor/IIssueExtensions.cs b/src/Cake.Issues.PullRequests.AppVeyor/IIssueExtensions.cs new file mode 100644 index 000000000..c8060d917 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AppVeyor/IIssueExtensions.cs @@ -0,0 +1,31 @@ +namespace Cake.Issues.PullRequests.AppVeyor +{ + using Cake.Common.Build.AppVeyor; + + /// + /// Extensions for . + /// + internal static class IIssueExtensions + { + /// + /// Returns the corresponding category of an AppVeyor message for an issue priority. + /// + /// Priority of the issue. + /// Category for the AppVeyor message. + public static AppVeyorMessageCategoryType ToAppVeyorMessageCategoryType(this int? priority) + { + if (priority == null) + { + return AppVeyorMessageCategoryType.Warning; + } + + return priority switch + { + (int)IssuePriority.Error => AppVeyorMessageCategoryType.Error, + (int)IssuePriority.Warning => AppVeyorMessageCategoryType.Warning, + (int)IssuePriority.Hint or (int)IssuePriority.Suggestion => AppVeyorMessageCategoryType.Information, + _ => AppVeyorMessageCategoryType.Warning, + }; + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/AzureDevOpsPullRequestSystemSettingsTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/AzureDevOpsPullRequestSystemSettingsTests.cs new file mode 100644 index 000000000..b5733e08b --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/AzureDevOpsPullRequestSystemSettingsTests.cs @@ -0,0 +1,84 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests +{ + using System; + using Cake.AzureDevOps.Authentication; + using Cake.Issues.Testing; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AzureDevOpsPullRequestSystemSettingsTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_RepositoryUrl_For_SourceRefName_Is_Null() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(null, "foo", new AzureDevOpsNtlmCredentials())); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_SourceRefName_Is_Null() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(new Uri("http://example.com"), null, new AzureDevOpsNtlmCredentials())); + + // Then + result.IsArgumentNullException("sourceRefName"); + } + + [Fact] + public void Should_Throw_If_SourceRefName_Is_Empty() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(new Uri("http://example.com"), string.Empty, new AzureDevOpsNtlmCredentials())); + + // Then + result.IsArgumentOutOfRangeException("sourceRefName"); + } + + [Fact] + public void Should_Throw_If_SourceRefName_Is_WhiteSpace() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(new Uri("http://example.com"), " ", new AzureDevOpsNtlmCredentials())); + + // Then + result.IsArgumentOutOfRangeException("sourceRefName"); + } + + [Fact] + public void Should_Throw_If_RepositoryUrl_For_PullRequestId_Is_Null() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(null, 0, new AzureDevOpsNtlmCredentials())); + + // Then + result.IsArgumentNullException("repositoryUrl"); + } + + [Fact] + public void Should_Throw_If_Credentials_For_PullRequestId_Are_Null() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(new Uri("http://example.com"), 42, null)); + + // Then + result.IsArgumentNullException("credentials"); + } + + [Fact] + public void Should_Throw_If_Credentials_For_SourceBranch_Are_Null() + { + // Given / When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystemSettings(new Uri("http://example.com"), "feature/foo", null)); + + // Then + result.IsArgumentNullException("credentials"); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/AzureDevOpsPullRequestSystemTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/AzureDevOpsPullRequestSystemTests.cs new file mode 100644 index 000000000..73bea308f --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/AzureDevOpsPullRequestSystemTests.cs @@ -0,0 +1,48 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests +{ + using System; + using Cake.AzureDevOps.Authentication; + using Cake.Core.Diagnostics; + using Cake.Issues.Testing; + using Cake.Testing; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AzureDevOpsPullRequestSystemTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given + const ICakeLog log = null; + var settings = + new AzureDevOpsPullRequestSystemSettings( + new Uri("https://google.com"), + 123, + new AzureDevOpsNtlmCredentials()); + + // When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystem(log, settings)); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var log = new FakeLog(); + const AzureDevOpsPullRequestSystemSettings settings = null; + + // When + var result = Record.Exception(() => new AzureDevOpsPullRequestSystem(log, settings)); + + // Then + result.IsArgumentNullException("settings"); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Cake.Issues.PullRequests.AzureDevOps.Tests.csproj b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Cake.Issues.PullRequests.AzureDevOps.Tests.csproj new file mode 100644 index 000000000..52d235744 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Cake.Issues.PullRequests.AzureDevOps.Tests.csproj @@ -0,0 +1,38 @@ + + + + net6.0;net7.0;net8.0 + false + Cake.Issues.PullRequests.AzureDevOps + Copyright © BBT Software AG and contributors + Tests for the Cake.Issues.PullRequests.AzureDevOps addin + BBT Software AG and contributors + + + + ..\Cake.Issues.Tests.ruleset + latest + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsCheckingCommitIdCapabilityTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsCheckingCommitIdCapabilityTests.cs new file mode 100644 index 000000000..900eb8a9a --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsCheckingCommitIdCapabilityTests.cs @@ -0,0 +1,44 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests.Capabilities +{ + using Cake.Core.Diagnostics; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + using Cake.Issues.Testing; + using Cake.Testing; + using NSubstitute; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AzureDevOpsCheckingCommitIdCapabilityTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given + const ICakeLog log = null; + var pullRequestSystem = Substitute.For(); + + // When + var result = Record.Exception(() => new AzureDevOpsCheckingCommitIdCapability(log, pullRequestSystem)); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_PullRequestSystem_Is_Null() + { + // Given + var log = new FakeLog(); + const AzureDevOpsPullRequestSystem pullRequestSystem = null; + + // When + var result = Record.Exception(() => new AzureDevOpsCheckingCommitIdCapability(log, pullRequestSystem)); + + // Then + result.IsArgumentNullException("pullRequestSystem"); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsDiscussionThreadsCapabilityTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsDiscussionThreadsCapabilityTests.cs new file mode 100644 index 000000000..6991f3beb --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsDiscussionThreadsCapabilityTests.cs @@ -0,0 +1,44 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests.Capabilities +{ + using Cake.Core.Diagnostics; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + using Cake.Issues.Testing; + using Cake.Testing; + using NSubstitute; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AzureDevOpsDiscussionThreadsCapabilityTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given + const ICakeLog log = null; + var pullRequestSystem = Substitute.For(); + + // When + var result = Record.Exception(() => new AzureDevOpsDiscussionThreadsCapability(log, pullRequestSystem)); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_PullRequestSystem_Is_Null() + { + // Given + var log = new FakeLog(); + const AzureDevOpsPullRequestSystem pullRequestSystem = null; + + // When + var result = Record.Exception(() => new AzureDevOpsDiscussionThreadsCapability(log, pullRequestSystem)); + + // Then + result.IsArgumentNullException("pullRequestSystem"); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsFilteringByModifiedFilesCapabilityTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsFilteringByModifiedFilesCapabilityTests.cs new file mode 100644 index 000000000..a70952589 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/AzureDevOpsFilteringByModifiedFilesCapabilityTests.cs @@ -0,0 +1,44 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests.Capabilities +{ + using Cake.Core.Diagnostics; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + using Cake.Issues.Testing; + using Cake.Testing; + using NSubstitute; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AzureDevOpsFilteringByModifiedFilesCapabilityTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given + const ICakeLog log = null; + var pullRequestSystem = Substitute.For(); + + // When + var result = Record.Exception(() => new AzureDevOpsFilteringByModifiedFilesCapability(log, pullRequestSystem)); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_PullRequestSystem_Is_Null() + { + // Given + var log = new FakeLog(); + const AzureDevOpsPullRequestSystem pullRequestSystem = null; + + // When + var result = Record.Exception(() => new AzureDevOpsFilteringByModifiedFilesCapability(log, pullRequestSystem)); + + // Then + result.IsArgumentNullException("pullRequestSystem"); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/CommentExtensionsTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/CommentExtensionsTests.cs new file mode 100644 index 000000000..18ad15c6d --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/CommentExtensionsTests.cs @@ -0,0 +1,65 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests.Capabilities +{ + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class CommentExtensionsTests + { + public sealed class TheToPullRequestDiscussionCommentExtension + { + [Fact] + public void Should_Throw_If_Comment_Is_Null() + { + // Given + const AzureDevOpsComment comment = null; + + // When + var result = Record.Exception(() => comment.ToPullRequestDiscussionComment()); + + // Then + result.IsArgumentNullException("comment"); + } + + [Fact] + public void Should_Set_Correct_Content() + { + // Given + const string content = "foo"; + var comment = + new AzureDevOpsComment + { + Content = content, + }; + + // When + var result = comment.ToPullRequestDiscussionComment(); + + // Then + result.Content.ShouldBe(content); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Set_Correct_IsDeleted(bool isDeleted) + { + // Given + var comment = + new AzureDevOpsComment + { + IsDeleted = isDeleted, + }; + + // When + var result = comment.ToPullRequestDiscussionComment(); + + // Then + result.IsDeleted.ShouldBe(isDeleted); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/CommentThreadStatusExtensionsTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/CommentThreadStatusExtensionsTests.cs new file mode 100644 index 000000000..16bb5762b --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/CommentThreadStatusExtensionsTests.cs @@ -0,0 +1,87 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests.Capabilities +{ + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + using Shouldly; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class CommentThreadStatusExtensionsTests + { + public sealed class TheToPullRequestDiscussionStatusExtension + { + [Theory] + [InlineData( + AzureDevOpsCommentThreadStatus.Unknown, + PullRequestDiscussionStatus.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Active, + PullRequestDiscussionStatus.Active)] + [InlineData( + AzureDevOpsCommentThreadStatus.Pending, + PullRequestDiscussionStatus.Active)] + [InlineData( + AzureDevOpsCommentThreadStatus.Fixed, + PullRequestDiscussionStatus.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.WontFix, + PullRequestDiscussionStatus.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.Closed, + PullRequestDiscussionStatus.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.ByDesign, + PullRequestDiscussionStatus.Resolved)] + public void Should_Return_Correct_Value( + AzureDevOpsCommentThreadStatus status, + PullRequestDiscussionStatus expectedResult) + { + // Given + + // When + var result = status.ToPullRequestDiscussionStatus(); + + // Then + result.ShouldBe(expectedResult); + } + } + + public sealed class TheToPullRequestDiscussionResolutionExtension + { + [Theory] + [InlineData( + AzureDevOpsCommentThreadStatus.Unknown, + PullRequestDiscussionResolution.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Active, + PullRequestDiscussionResolution.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Pending, + PullRequestDiscussionResolution.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Fixed, + PullRequestDiscussionResolution.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.WontFix, + PullRequestDiscussionResolution.WontFix)] + [InlineData( + AzureDevOpsCommentThreadStatus.Closed, + PullRequestDiscussionResolution.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.ByDesign, + PullRequestDiscussionResolution.Resolved)] + public void Should_Return_Correct_Value( + AzureDevOpsCommentThreadStatus status, + PullRequestDiscussionResolution expectedResult) + { + // Given + + // When + var result = status.ToPullRequestDiscussionResolution(); + + // Then + result.ShouldBe(expectedResult); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/GitPullRequestCommentThreadExtensionsTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/GitPullRequestCommentThreadExtensionsTests.cs new file mode 100644 index 000000000..4ea92d6c3 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/Capabilities/GitPullRequestCommentThreadExtensionsTests.cs @@ -0,0 +1,766 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests.Capabilities +{ + using System.Collections.Generic; + using System.Linq; + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class GitPullRequestCommentThreadExtensionsTests + { + public sealed class TheToPullRequestDiscussionThreadExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + + // When + var result = Record.Exception(() => thread.ToPullRequestDiscussionThread()); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Throw_If_Comments_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = null, + Properties = new Dictionary(), + }; + + // When + var result = Record.Exception(() => thread.ToPullRequestDiscussionThread()); + + // Then + result.IsInvalidOperationException("Comments list is not created."); + } + + [Fact] + public void Should_Not_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.CommentSource.ShouldBe(default); + } + + [Fact] + public void Should_Set_Correct_Id() + { + // Given + const int id = 123; + const AzureDevOpsCommentThreadStatus status = AzureDevOpsCommentThreadStatus.Active; + const string filePath = "/foo.cs"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.Id.ShouldBe(id); + } + + [Theory] + [InlineData( + AzureDevOpsCommentThreadStatus.Unknown, + PullRequestDiscussionStatus.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Active, + PullRequestDiscussionStatus.Active)] + [InlineData( + AzureDevOpsCommentThreadStatus.Pending, + PullRequestDiscussionStatus.Active)] + [InlineData( + AzureDevOpsCommentThreadStatus.Fixed, + PullRequestDiscussionStatus.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.WontFix, + PullRequestDiscussionStatus.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.Closed, + PullRequestDiscussionStatus.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.ByDesign, + PullRequestDiscussionStatus.Resolved)] + public void Should_Set_Correct_Status( + AzureDevOpsCommentThreadStatus status, + PullRequestDiscussionStatus expectedResult) + { + // Given + const int id = 123; + const string filePath = "/foo.cs"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.Status.ShouldBe(expectedResult); + } + + [Theory] + [InlineData("/foo.cs", "foo.cs")] + public void Should_Set_Correct_FilePath(string filePath, string expectedResult) + { + // Given + const int id = 123; + const AzureDevOpsCommentThreadStatus status = AzureDevOpsCommentThreadStatus.Active; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.AffectedFileRelativePath.ToString().ShouldBe(expectedResult); + } + + [Fact] + public void Should_Set_Correct_FilePath_If_ThreadContext_Is_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.AffectedFileRelativePath.ShouldBeNull(); + } + + [Fact] + public void Should_Set_Correct_Comments() + { + // Given + const int id = 123; + const AzureDevOpsCommentThreadStatus status = AzureDevOpsCommentThreadStatus.Active; + const string filePath = "/foo.cs"; + const string commentContent = "foo"; + const bool commentIsDeleted = false; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List + { + new() + { + Content = commentContent, + IsDeleted = commentIsDeleted, + }, + }, + Properties = new Dictionary(), + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.Comments.Count.ShouldBe(1); + result.Comments.Single().Content.ShouldBe(commentContent); + result.Comments.Single().IsDeleted.ShouldBe(commentIsDeleted); + } + + [Fact] + public void Should_Set_Correct_CommentSource() + { + // Given + const int id = 123; + const AzureDevOpsCommentThreadStatus status = AzureDevOpsCommentThreadStatus.Active; + const string filePath = "/foo.cs"; + const string commentSource = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetCommentSource(commentSource); + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.CommentSource.ShouldBe(commentSource); + } + + [Fact] + public void Should_Set_Correct_ProviderType() + { + // Given + const int id = 123; + const AzureDevOpsCommentThreadStatus status = AzureDevOpsCommentThreadStatus.Active; + const string filePath = "/foo.cs"; + const string providerType = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetProviderType(providerType); + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.ProviderType.ShouldBe(providerType); + } + + [Theory] + [InlineData( + AzureDevOpsCommentThreadStatus.Unknown, + PullRequestDiscussionResolution.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Active, + PullRequestDiscussionResolution.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Pending, + PullRequestDiscussionResolution.Unknown)] + [InlineData( + AzureDevOpsCommentThreadStatus.Fixed, + PullRequestDiscussionResolution.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.WontFix, + PullRequestDiscussionResolution.WontFix)] + [InlineData( + AzureDevOpsCommentThreadStatus.Closed, + PullRequestDiscussionResolution.Resolved)] + [InlineData( + AzureDevOpsCommentThreadStatus.ByDesign, + PullRequestDiscussionResolution.Resolved)] + public void Should_Set_Correct_Resolution( + AzureDevOpsCommentThreadStatus status, + PullRequestDiscussionResolution expectedResult) + { + // Given + const int id = 123; + const string filePath = "/foo.cs"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = id, + Status = status, + FilePath = filePath, + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + var result = thread.ToPullRequestDiscussionThread(); + + // Then + result.Resolution.ShouldBe(expectedResult); + } + } + + public sealed class TheGetCommentSourceExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + + // When + var result = Record.Exception(() => thread.GetCommentSource()); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Not_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + + // When + var result = thread.GetCommentSource(); + + // Then + result.ShouldBe(default); + } + + [Fact] + public void Should_Return_Comment_Source() + { + // Given + const string commentSource = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetCommentSource(commentSource); + + // When + var result = thread.GetCommentSource(); + + // Then + result.ShouldBe(commentSource); + } + } + + public sealed class TheGetProviderTypeExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + + // When + var result = Record.Exception(() => thread.GetProviderType()); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Not_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + + // When + var result = thread.GetProviderType(); + + // Then + result.ShouldBe(default); + } + + [Fact] + public void Should_Return_ProviderType() + { + // Given + const string providerType = "fooProv"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetProviderType(providerType); + + // When + var result = thread.GetProviderType(); + + // Then + result.ShouldBe(providerType); + } + } + + public sealed class TheSetCommentSourceExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + const string value = "foo"; + + // When + var result = Record.Exception(() => thread.SetCommentSource(value)); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + const string value = "foo"; + + // When + var result = Record.Exception(() => thread.SetCommentSource(value)); + + // Then + result.IsInvalidOperationException("Properties collection is not created."); + } + + [Fact] + public void Should_Set_Comment_Source() + { + // Given + const string commentSource = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + thread.SetCommentSource(commentSource); + + // Then + thread.GetCommentSource().ShouldBe(commentSource); + } + } + + public sealed class TheSetProviderTypeExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + const string value = "foo"; + + // When + var result = Record.Exception(() => thread.SetProviderType(value)); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + var value = "foo"; + + // When + var result = Record.Exception(() => thread.SetProviderType(value)); + + // Then + result.IsInvalidOperationException("Properties collection is not created."); + } + + [Fact] + public void Should_Set_ProviderType() + { + // Given + const string providerType = "provType"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + thread.SetProviderType(providerType); + + // Then + thread.GetProviderType().ShouldBe(providerType); + } + } + + public sealed class TheIsCommentSourceExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + const string value = "foo"; + + // When + var result = Record.Exception(() => thread.IsCommentSource(value)); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Not_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + const string value = "foo"; + + // When + var result = thread.IsCommentSource(value); + + // Then + result.ShouldBeFalse(); + } + + [Fact] + public void Should_Return_True_For_Existing_Comment_Source() + { + // Given + const string commentSource = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetCommentSource(commentSource); + + // When + var result = thread.IsCommentSource(commentSource); + + // Then + result.ShouldBeTrue(); + } + + [Fact] + public void Should_Return_False_For_Non_Existing_Comment_Source() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetCommentSource("foo"); + + // When + var result = thread.IsCommentSource("bar"); + + // Then + result.ShouldBeFalse(); + } + } + + public sealed class TheGetIssueMessageExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + + // When + var result = Record.Exception(() => thread.GetIssueMessage()); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Not_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + + // When + var result = thread.GetIssueMessage(); + + // Then + result.ShouldBe(default); + } + + [Fact] + public void Should_Return_Message() + { + // Given + const string message = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + thread.SetIssueMessage(message); + + // When + var result = thread.GetIssueMessage(); + + // Then + result.ShouldBe(message); + } + } + + public sealed class TheSetIssueMessageExtension + { + [Fact] + public void Should_Throw_If_Thread_Is_Null() + { + // Given + const AzureDevOpsPullRequestCommentThread thread = null; + const string value = "foo"; + + // When + var result = Record.Exception(() => thread.SetIssueMessage(value)); + + // Then + result.IsArgumentNullException("thread"); + } + + [Fact] + public void Should_Throw_If_Properties_Are_Null() + { + // Given + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = null, + }; + const string value = "foo"; + + // When + var result = Record.Exception(() => thread.SetIssueMessage(value)); + + // Then + result.IsInvalidOperationException("Properties collection is not created."); + } + + [Fact] + public void Should_Return_Message() + { + // Given + const string message = "foo"; + var thread = + new AzureDevOpsPullRequestCommentThread + { + Id = 123, + Status = AzureDevOpsCommentThreadStatus.Active, + FilePath = "/foo.cs", + Comments = new List(), + Properties = new Dictionary(), + }; + + // When + thread.SetIssueMessage(message); + + // Then + thread.GetIssueMessage().ShouldBe(message); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps.Tests/ContentProviderTests.cs b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/ContentProviderTests.cs new file mode 100644 index 000000000..ba2c98820 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps.Tests/ContentProviderTests.cs @@ -0,0 +1,77 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Tests +{ + using System; + using Shouldly; + using Xunit; + + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class ContentProviderTests + { + public sealed class TheGetContentMethod + { + [Theory] + [InlineData( + "foo.cs", + 123, + "Some message", + IssuePriority.Warning, + "foo", + null, + "foo: Some message")] + [InlineData( + "foo.cs", + 123, + "Some message", + IssuePriority.Warning, + "", + null, + "Some message")] + [InlineData( + "foo.cs", + 123, + "Some message", + IssuePriority.Warning, + " ", + null, + "Some message")] + [InlineData( + "foo.cs", + 123, + "Some message", + IssuePriority.Warning, + "foo", + "http://google.com", + "[foo](http://google.com/): Some message")] + public void Should_Return_Correct_Value( + string filePath, + int? line, + string message, + IssuePriority priority, + string rule, + string ruleUrl, + string expectedResult) + { + // Given + Uri ruleUri = null; + if (!string.IsNullOrWhiteSpace(ruleUrl)) + { + ruleUri = new Uri(ruleUrl); + } + + var issue = + IssueBuilder + .NewIssue(message, "ProviderType", "ProviderName") + .InFile(filePath, line) + .OfRule(rule, ruleUri) + .WithPriority(priority) + .Create(); + + // When + var result = ContentProvider.GetContent(issue); + + // Then + result.ShouldBe(expectedResult); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystem.cs b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystem.cs new file mode 100644 index 000000000..9060102cf --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystem.cs @@ -0,0 +1,316 @@ +namespace Cake.Issues.PullRequests.AzureDevOps +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using Cake.AzureDevOps.Repos.PullRequest; + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Cake.Issues.PullRequests.AzureDevOps.Capabilities; + + /// + /// Class for writing issues to Azure DevOps pull requests. + /// + internal sealed class AzureDevOpsPullRequestSystem : BasePullRequestSystem, IAzureDevOpsPullRequestSystem + { + private readonly AzureDevOpsPullRequestSystemSettings settings; + private readonly AzureDevOpsPullRequest azureDevOpsPullRequest; + + /// + /// Initializes a new instance of the class. + /// Connects to the Azure DevOps server using NTLM authentication. + /// + /// The Cake log context. + /// Settings for accessing Azure DevOps Server. + public AzureDevOpsPullRequestSystem(ICakeLog log, AzureDevOpsPullRequestSystemSettings settings) + : base(log) + { + settings.NotNull(nameof(settings)); + + this.settings = settings; + + if (settings.CheckCommitId) + { + this.AddCapability(new AzureDevOpsCheckingCommitIdCapability(log, this)); + this.Log.Information("Commit ID check capability is enabled."); + } + else + { + this.Log.Information("Commit ID check capability is disabled."); + } + + if (settings.ManageDiscussionThreadStatus) + { + this.AddCapability(new AzureDevOpsDiscussionThreadsCapability(log, this)); + this.Log.Information("Discussion thread status management capability is enabled."); + } + else + { + this.Log.Information("Discussion thread status management capability is disabled."); + } + + // Filtering by modified files is always required as we otherwise no longer can compare issues + // in a subsequent run as we lose information about file and line. + // See https://github.com/cake-contrib/Cake.Issues.PullRequests.AzureDevOps/issues/46#issuecomment-419149355 + this.AddCapability(new AzureDevOpsFilteringByModifiedFilesCapability(log, this)); + + this.azureDevOpsPullRequest = new AzureDevOpsPullRequest(log, settings); + } + + /// + AzureDevOpsPullRequest IAzureDevOpsPullRequestSystem.AzureDevOpsPullRequest => this.azureDevOpsPullRequest; + + /// + public override bool Initialize(IReportIssuesToPullRequestSettings settings) + { + // Fail initialization if no pull request could be found. + return base.Initialize(settings) && this.azureDevOpsPullRequest.HasPullRequestLoaded; + } + + /// + bool IAzureDevOpsPullRequestSystem.ValidatePullRequest() + { + return this.ValidatePullRequest(); + } + + /// + protected override void InternalPostDiscussionThreads(IEnumerable issues, string commentSource) + { + // ReSharper disable once PossibleMultipleEnumeration + issues.NotNull(nameof(issues)); + + if (!this.ValidatePullRequest()) + { + return; + } + + // ReSharper disable once PossibleMultipleEnumeration + var threads = this.CreateDiscussionThreads(issues, commentSource).ToList(); + + if (threads.Count == 0) + { + this.Log.Verbose("No threads to post"); + return; + } + + foreach (var thread in threads) + { + this.azureDevOpsPullRequest.CreateCommentThread(thread); + } + + this.Log.Information("Posted {0} discussion threads", threads.Count); + } + + private static void AddCodeFlowProperties( + IIssue issue, + int iterationId, + int changeTrackingId, + Dictionary properties) + { + issue.NotNull(nameof(issue)); + properties.NotNull(nameof(properties)); + + properties.Add("Microsoft.VisualStudio.Services.CodeReview.ItemPath", "/" + issue.AffectedFileRelativePath); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.Right.StartLine", issue.Line); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.Right.EndLine", issue.EndLine ?? issue.Line); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.Right.StartOffset", issue.Column ?? 0); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.Right.EndOffset", issue.EndColumn ?? 1); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.FirstComparingIteration", iterationId); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.SecondComparingIteration", iterationId); + properties.Add("Microsoft.VisualStudio.Services.CodeReview.ChangeTrackingId", changeTrackingId); + } + + /// + /// Validates if a pull request could be found. + /// Depending on + /// the pull request instance can not be successfully loaded. + /// + /// True if a valid pull request instance exists. + private bool ValidatePullRequest() + { + if (this.azureDevOpsPullRequest.HasPullRequestLoaded) + { + return true; + } + + this.Log.Verbose("Skipping, since no pull request instance could be found."); + return false; + } + + private List CreateDiscussionThreads( + IEnumerable issues, + string commentSource) + { + // ReSharper disable once PossibleMultipleEnumeration + issues.NotNull(nameof(issues)); + + if (this.azureDevOpsPullRequest.CodeReviewId <= 0) + { + this.Log.Error("Skipping creation of discussion thread since code review ID is not set."); + return []; + } + + this.Log.Verbose("Creating new discussion threads"); + + // Code flow properties + var iterationId = this.GetCodeFlowLatestIterationId(); + var changes = this.GetCodeFlowChanges(iterationId).ToList(); + + // Filter issues not related to a file. + if (!this.settings.ReportIssuesNotRelatedToAFile) + { + // ReSharper disable once PossibleMultipleEnumeration + issues = issues.Where(x => x.AffectedFileRelativePath != null); + } + + var result = new List(); + + // ReSharper disable once PossibleMultipleEnumeration + foreach (var issue in issues) + { + var changeTrackingId = + this.TryGetCodeFlowChangeTrackingId(changes, issue.AffectedFileRelativePath); + if (changeTrackingId < 0) + { + // Don't post comment if we couldn't determine the change. + this.Log.Information( + "Skipping discussion comment for the issue at line {0} from {1} since change tracking ID could not be determined", + issue.Line, + issue.AffectedFileRelativePath); + continue; + } + + this.Log.Information( + "Creating a discussion comment for the issue at line {0} from {1}", + issue.Line, + issue.AffectedFileRelativePath); + + var discussionComment = new AzureDevOpsComment + { + CommentType = AzureDevOpsCommentType.System, + IsDeleted = false, + Content = ContentProvider.GetContent(issue), + }; + + var newThread = new AzureDevOpsPullRequestCommentThread() + { + Status = AzureDevOpsCommentThreadStatus.Active, + Comments = new List { discussionComment }, + Properties = this.GetThreadProperties(changeTrackingId, issue, iterationId), + }; + + // Add a custom property to be able to distinguish all comments created this way. + newThread.SetCommentSource(commentSource); + + // Add custom property for identifying the comment for subsequent runs + newThread.SetCommentIdentifier(issue.Identifier); + + // Add a custom property to be able to distinguish all comments by provider type later on + newThread.SetProviderType(issue.ProviderType); + + // Add a custom property to be able to return issue message from existing threads, + // without any formatting done by this addin, back to Cake.Issues.PullRequests. + newThread.SetIssueMessage(issue.MessageText); + + result.Add(newThread); + } + + return result; + } + + private Dictionary GetThreadProperties( + int changeTrackingId, + IIssue issue, + int iterationId) + { + issue.NotNull(nameof(issue)); + + var properties = new Dictionary(); + + if (issue.AffectedFileRelativePath != null) + { + if (this.azureDevOpsPullRequest.CodeReviewId > 0) + { + AddCodeFlowProperties(issue, iterationId, changeTrackingId, properties); + } + else + { + throw new NotSupportedException("Legacy code reviews are not supported."); + } + } + + // An Azure DevOps UI extension will recognize this and format the comments differently. + properties.Add("CodeAnalysisThreadType", "CodeAnalysisIssue"); + + return properties; + } + + private int GetCodeFlowLatestIterationId() + { + var iterationId = this.azureDevOpsPullRequest.GetLatestIterationId(); + this.Log.Verbose("Determined iteration ID: {0}", iterationId); + return iterationId; + } + + private List GetCodeFlowChanges(int iterationId) + { + var changes = + this.azureDevOpsPullRequest.GetIterationChanges(iterationId); + + if (changes == null) + { + this.Log.Warning("Changes for iteration {0} could not be detected", iterationId); + return []; + } + + var result = changes.ToList(); + this.Log.Verbose("Change count: {0}", result.Count); + + return result; + } + + private int TryGetCodeFlowChangeTrackingId(IEnumerable changes, FilePath path) + { + // ReSharper disable once PossibleMultipleEnumeration + changes.NotNull(nameof(changes)); + path.NotNull(nameof(path)); + + // ReSharper disable once PossibleMultipleEnumeration + var change = + changes + .Where(x => x.ItemPath != null && x.ItemPath.FullPath == "/" + path) + .ToList(); + + switch (change.Count) + { + case 0: + this.Log.Error( + "Cannot post a comment for the file {0} because no changes on the pull request server could be found.", + path); + return -1; + case > 1: + this.Log.Error( + "Cannot post a comment for the file {0} because more than one change has been found on the pull request server:" + Environment.NewLine + "{1}", + path, + string.Join( + Environment.NewLine, + change.Select( + x => string.Format( + CultureInfo.InvariantCulture, + " ID: {0}, Path: {1}", + x.ChangeId, + x.ItemPath)))); + return -1; + } + + var changeTrackingId = change.Single().ChangeTrackingId; + this.Log.Verbose( + "Determined ChangeTrackingId of {0} for {1}", + changeTrackingId, + path); + return changeTrackingId; + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases.PullRequestSystem.cs b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases.PullRequestSystem.cs new file mode 100644 index 000000000..acf2ce0bf --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases.PullRequestSystem.cs @@ -0,0 +1,198 @@ +namespace Cake.Issues.PullRequests.AzureDevOps +{ + using System; + using Cake.AzureDevOps.Authentication; + using Cake.Core; + using Cake.Core.Annotations; + + /// + /// Contains functionality related to . + /// + public static partial class AzureDevOpsPullRequestSystemAliases + { + /// + /// Gets an object for writing issues to Azure DevOps pull request in a specific repository and for a + /// specific source branch. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// Branch for which the pull request is made. + /// Credentials to use to authenticate against Azure DevOps. + /// Object for writing issues to Azure DevOps pull request. + /// + /// Report code analysis issues reported as MsBuild warnings to an Azure DevOps pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AzureDevOpsPullRequests( + this ICakeContext context, + Uri repositoryUrl, + string sourceBranch, + IAzureDevOpsCredentials credentials) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + sourceBranch.NotNullOrWhiteSpace(nameof(sourceBranch)); + credentials.NotNull(nameof(credentials)); + + return context.AzureDevOpsPullRequests(new AzureDevOpsPullRequestSystemSettings(repositoryUrl, sourceBranch, credentials)); + } + + /// + /// Gets an object for writing issues to Azure DevOps pull request in a specific repository and with a specific ID. + /// + /// The context. + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// ID of the pull request. + /// Credentials to use to authenticate against Azure DevOps. + /// Object for writing issues to Azure DevOps pull request. + /// + /// Report code analysis issues reported as MsBuild warnings to an Azure DevOps Server pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AzureDevOpsPullRequests( + this ICakeContext context, + Uri repositoryUrl, + int pullRequestId, + IAzureDevOpsCredentials credentials) + { + context.NotNull(nameof(context)); + repositoryUrl.NotNull(nameof(repositoryUrl)); + credentials.NotNull(nameof(credentials)); + + return context.AzureDevOpsPullRequests(new AzureDevOpsPullRequestSystemSettings(repositoryUrl, pullRequestId, credentials)); + } + + /// + /// Gets an object for writing issues to Azure DevOps pull request where all required data is taken + /// from the environment variables set by Azure Pipelines. + /// + /// The context. + /// Credentials to use to authenticate against Azure DevOps. + /// Object for writing issues to Azure DevOps pull request. + /// + /// Report code analysis issues reported as MsBuild warnings to an Azure DevOps Server pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AzureDevOpsPullRequests( + this ICakeContext context, + IAzureDevOpsCredentials credentials) + { + context.NotNull(nameof(context)); + credentials.NotNull(nameof(credentials)); + + return context.AzureDevOpsPullRequests(new AzureDevOpsPullRequestSystemSettings(credentials)); + } + + /// + /// Gets an object for writing issues to Azure DevOps pull request where all required data (including authentication token) + /// is taken from the environment variables set by Azure Pipelines. + /// + /// The context. + /// Object for writing issues to Azure DevOps pull request. + /// + /// Report code analysis issues reported as MsBuild warnings to an Azure DevOps pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AzureDevOpsPullRequests( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return context.AzureDevOpsPullRequests(new AzureDevOpsPullRequestSystemSettings()); + } + + /// + /// Gets an object for writing issues to Azure DevOps pull request using the specified settings. + /// + /// The context. + /// Settings for accessing the pull request system. + /// Object for writing issues to Azure DevOps pull request. + /// + /// Report code analysis issues reported as MsBuild warnings to an Azure DevOps Server pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem AzureDevOpsPullRequests( + this ICakeContext context, + AzureDevOpsPullRequestSystemSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new AzureDevOpsPullRequestSystem(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases.cs b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases.cs new file mode 100644 index 000000000..331f1d74b --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemAliases.cs @@ -0,0 +1,14 @@ +namespace Cake.Issues.PullRequests.AzureDevOps +{ + using System.Diagnostics.CodeAnalysis; + using Cake.Core.Annotations; + + /// + /// Contains functionality related to writing code analysis issues to Azure DevOps pull requests. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + [SuppressMessage("ReSharper", "RedundantTypeDeclarationBody", Justification = "Fixing will crash StyleCop")] + public static partial class AzureDevOpsPullRequestSystemAliases + { + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemSettings.cs b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemSettings.cs new file mode 100644 index 000000000..31e54202d --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/AzureDevOpsPullRequestSystemSettings.cs @@ -0,0 +1,93 @@ +namespace Cake.Issues.PullRequests.AzureDevOps +{ + using System; + using Cake.AzureDevOps.Authentication; + using Cake.AzureDevOps.Repos.PullRequest; + + /// + /// Settings for . + /// + public class AzureDevOpsPullRequestSystemSettings : AzureDevOpsPullRequestSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// Branch for which the pull request is made. + /// Credentials to use to authenticate against Azure DevOps. + public AzureDevOpsPullRequestSystemSettings(Uri repositoryUrl, string sourceBranch, IAzureDevOpsCredentials credentials) + : base(repositoryUrl, sourceBranch, credentials) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Full URL of the Git repository, + /// eg. http://myserver:8080/tfs/defaultcollection/myproject/_git/myrepository. + /// Supported URL schemes are HTTP, HTTPS and SSH. + /// URLs using SSH scheme are converted to HTTPS. + /// ID of the pull request. + /// Credentials to use to authenticate against Azure DevOps. + public AzureDevOpsPullRequestSystemSettings(Uri repositoryUrl, int pullRequestId, IAzureDevOpsCredentials credentials) + : base(repositoryUrl, pullRequestId, credentials) + { + } + + /// + /// Initializes a new instance of the class + /// based on the instance of a class. + /// + /// Settings containing the parameters. + public AzureDevOpsPullRequestSystemSettings(AzureDevOpsPullRequestSettings settings) + : base(settings) + { + } + + /// + /// Initializes a new instance of the class + /// based on the environment variables set by the Azure Pipelines. + /// + /// Credentials to use to authenticate against Azure DevOps. + public AzureDevOpsPullRequestSystemSettings(IAzureDevOpsCredentials credentials) + : base(credentials) + { + } + + /// + /// Initializes a new instance of the class + /// based on the environment variables set by the Azure Pipelines using the build authentication token. + /// + public AzureDevOpsPullRequestSystemSettings() + : base(UsingAzurePipelinesOAuthToken()) + { + } + + /// + /// Gets or sets a value indicating whether pull request system should check if commit Id + /// is still up to date before posting comments. + /// Default value is true. + /// + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public bool CheckCommitId { get; set; } = true; + + /// + /// Gets or sets a value indicating whether discussion threads should automatically be + /// resolved oder reopened. + /// Default value is true. + /// + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public bool ManageDiscussionThreadStatus { get; set; } = true; + + /// + /// Gets or sets a value indicating whether issues not related to a file should be posted + /// as comments or not. + /// Default value is false. + /// + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public bool ReportIssuesNotRelatedToAFile { get; set; } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Cake.Issues.PullRequests.AzureDevOps.csproj b/src/Cake.Issues.PullRequests.AzureDevOps/Cake.Issues.PullRequests.AzureDevOps.csproj new file mode 100644 index 000000000..eac02928b --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Cake.Issues.PullRequests.AzureDevOps.csproj @@ -0,0 +1,41 @@ + + + + net6.0;net7.0;net8.0 + Azure DevOps support for the Cake.Issues addin for Cake Build Automation System + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + bin\$(Configuration)\$(TargetFramework)\Cake.Issues.PullRequests.AzureDevOps.xml + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCheckingCommitIdCapability.cs b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCheckingCommitIdCapability.cs new file mode 100644 index 000000000..59beb3666 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCheckingCommitIdCapability.cs @@ -0,0 +1,24 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Capabilities +{ + using Cake.Core.Diagnostics; + + /// + /// Implementation of a for . + /// + /// The Cake log context. + /// Pull request system to which this capability belongs. + internal class AzureDevOpsCheckingCommitIdCapability(ICakeLog log, IAzureDevOpsPullRequestSystem pullRequestSystem) + : BaseCheckingCommitIdCapability(log, pullRequestSystem) + { + /// + public override string GetLastSourceCommitId() + { + if (!this.PullRequestSystem.ValidatePullRequest()) + { + return string.Empty; + } + + return this.PullRequestSystem.AzureDevOpsPullRequest.LastSourceCommitId; + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCommentExtensions.cs b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCommentExtensions.cs new file mode 100644 index 000000000..390ee96ee --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCommentExtensions.cs @@ -0,0 +1,26 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Capabilities +{ + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + + /// + /// Extensions for . + /// + internal static class AzureDevOpsCommentExtensions + { + /// + /// Converts a from Azure DevOps to a as used in this addin. + /// + /// Azure DevOps comment to convert. + /// Converted comment. + public static IPullRequestDiscussionComment ToPullRequestDiscussionComment(this AzureDevOpsComment comment) + { + comment.NotNull(nameof(comment)); + + return new PullRequestDiscussionComment() + { + Content = comment.Content, + IsDeleted = comment.IsDeleted, + }; + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCommentThreadStatusExtensions.cs b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCommentThreadStatusExtensions.cs new file mode 100644 index 000000000..aa8aa06ef --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsCommentThreadStatusExtensions.cs @@ -0,0 +1,56 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Capabilities +{ + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + + /// + /// Extensions for enumeration. + /// + internal static class AzureDevOpsCommentThreadStatusExtensions + { + /// + /// Converts a from Azure DevOps to a as used in this addin. + /// + /// Azure DevOps status to convert. + /// Converted status. + public static PullRequestDiscussionStatus ToPullRequestDiscussionStatus(this AzureDevOpsCommentThreadStatus status) + { + return status switch + { + AzureDevOpsCommentThreadStatus.Unknown => + PullRequestDiscussionStatus.Unknown, + AzureDevOpsCommentThreadStatus.Active or + AzureDevOpsCommentThreadStatus.Pending => + PullRequestDiscussionStatus.Active, + AzureDevOpsCommentThreadStatus.Fixed or + AzureDevOpsCommentThreadStatus.WontFix or + AzureDevOpsCommentThreadStatus.Closed or + AzureDevOpsCommentThreadStatus.ByDesign => + PullRequestDiscussionStatus.Resolved, + _ => throw new PullRequestIssuesException("Unknown enumeration value"), + }; + } + + /// + /// Converts a from Azure DevOps to a as used in this addin. + /// + /// Azure DevOps status to convert. + /// Converted status. + public static PullRequestDiscussionResolution ToPullRequestDiscussionResolution(this AzureDevOpsCommentThreadStatus status) + { + return status switch + { + AzureDevOpsCommentThreadStatus.Unknown or + AzureDevOpsCommentThreadStatus.Active or + AzureDevOpsCommentThreadStatus.Pending => + PullRequestDiscussionResolution.Unknown, + AzureDevOpsCommentThreadStatus.Fixed or + AzureDevOpsCommentThreadStatus.Closed or + AzureDevOpsCommentThreadStatus.ByDesign => + PullRequestDiscussionResolution.Resolved, + AzureDevOpsCommentThreadStatus.WontFix => + PullRequestDiscussionResolution.WontFix, + _ => throw new PullRequestIssuesException("Unknown enumeration value"), + }; + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsDiscussionThreadsCapability.cs b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsDiscussionThreadsCapability.cs new file mode 100644 index 000000000..c3b33071e --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsDiscussionThreadsCapability.cs @@ -0,0 +1,76 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Capabilities +{ + using System.Collections.Generic; + using System.Linq; + using Cake.Core.Diagnostics; + + /// + /// Implementation of a for . + /// + /// The Cake log context. + /// Pull request system to which this capability belongs. + internal class AzureDevOpsDiscussionThreadsCapability(ICakeLog log, IAzureDevOpsPullRequestSystem pullRequestSystem) + : BaseDiscussionThreadsCapability(log, pullRequestSystem) + { + /// + protected override IEnumerable InternalFetchDiscussionThreads(string commentSource) + { + var threads = this.PullRequestSystem.AzureDevOpsPullRequest.GetCommentThreads(); + + var threadList = new List(); + foreach (var thread in threads) + { + if (!thread.IsCommentSource(commentSource)) + { + continue; + } + + var pullRequestThread = thread.ToPullRequestDiscussionThread(); + + // Comment identifier was introduced with Cake.Issues 0.9.0. + // To also support pull request written by previous versions of Cake.Issues + // we return the message without additional formatting in case no + // identifier was set on the thread. + if (string.IsNullOrEmpty(pullRequestThread.CommentIdentifier)) + { + pullRequestThread.CommentIdentifier = thread.GetIssueMessage(); + } + + // Assuming that the first comment is the one written by this addin, we replace the content + // containing additional formatting done by this addin with the original issue message. + pullRequestThread.Comments.First().Content = thread.GetIssueMessage(); + + threadList.Add(pullRequestThread); + } + + this.Log.Verbose("Found {0} discussion thread(s)", threadList.Count); + return threadList; + } + + /// + protected override void InternalResolveDiscussionThreads(IEnumerable threads) + { + // ReSharper disable once PossibleMultipleEnumeration + threads.NotNull(nameof(threads)); + + // ReSharper disable once PossibleMultipleEnumeration + foreach (var thread in threads) + { + this.PullRequestSystem.AzureDevOpsPullRequest.ResolveCommentThread(thread.Id); + } + } + + /// + protected override void InternalReopenDiscussionThreads(IEnumerable threads) + { + // ReSharper disable once PossibleMultipleEnumeration + threads.NotNull(nameof(threads)); + + // ReSharper disable once PossibleMultipleEnumeration + foreach (var thread in threads) + { + this.PullRequestSystem.AzureDevOpsPullRequest.ActivateCommentThread(thread.Id); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsFilteringByModifiedFilesCapability.cs b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsFilteringByModifiedFilesCapability.cs new file mode 100644 index 000000000..1cca4f522 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsFilteringByModifiedFilesCapability.cs @@ -0,0 +1,26 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Capabilities +{ + using System.Collections.Generic; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + + /// + /// Implementation of a for . + /// + /// + /// Initializes a new instance of the class. + /// + /// The Cake log context. + /// Pull request system to which this capability belongs. + internal class AzureDevOpsFilteringByModifiedFilesCapability(ICakeLog log, IAzureDevOpsPullRequestSystem pullRequestSystem) + : BaseFilteringByModifiedFilesCapability(log, pullRequestSystem) + { + /// + protected override IEnumerable InternalGetModifiedFilesInPullRequest() + { + this.Log.Verbose("Computing the list of files changed in this pull request..."); + + return this.PullRequestSystem.AzureDevOpsPullRequest.GetModifiedFiles(); + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsPullRequestCommentThreadExtensions.cs b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsPullRequestCommentThreadExtensions.cs new file mode 100644 index 000000000..17722993d --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/Capabilities/AzureDevOpsPullRequestCommentThreadExtensions.cs @@ -0,0 +1,149 @@ +namespace Cake.Issues.PullRequests.AzureDevOps.Capabilities +{ + using System.Linq; + using Cake.AzureDevOps.Repos.PullRequest.CommentThread; + + /// + /// Extensions for . + /// + internal static class AzureDevOpsPullRequestCommentThreadExtensions + { + private const string CommentSourcePropertyName = "CakeIssuesCommentSource"; + private const string CommentIdentifierPropertyName = "CakeIssuesCommentIdentifier"; + private const string IssueMessagePropertyName = "CakeIssuesIssueMessage"; + private const string ProviderTypePropertyName = "CakeIssuesProviderType"; + + /// + /// Converts a from Azure DevOps to a as used in this addin. + /// + /// Azure DevOps thread to convert. + /// Converted thread. + public static IPullRequestDiscussionThread ToPullRequestDiscussionThread(this AzureDevOpsPullRequestCommentThread thread) + { + thread.NotNull(nameof(thread)); + + return new PullRequestDiscussionThread( + thread.Id, + thread.Status.ToPullRequestDiscussionStatus(), + thread.FilePath, + thread.Comments.Select(x => x.ToPullRequestDiscussionComment())) + { + CommentSource = thread.GetCommentSource(), + CommentIdentifier = thread.GetCommentIdentifier(), + ProviderType = thread.GetProviderType(), + Resolution = thread.Status.ToPullRequestDiscussionResolution(), + }; + } + + /// + /// Gets the comment source value used to decorate comments created by this add-in. + /// + /// Thread to get the value from. + /// Comment source value. + public static string GetCommentSource(this AzureDevOpsPullRequestCommentThread thread) + { + thread.NotNull(nameof(thread)); + + return thread.GetValue(CommentSourcePropertyName); + } + + /// + /// Sets the comment source value used to decorate comments created by this addin. + /// + /// Thread for which the value should be set. + /// Value to set as comment source. + public static void SetCommentSource(this AzureDevOpsPullRequestCommentThread thread, string value) + { + thread.NotNull(nameof(thread)); + + thread.SetValue(CommentSourcePropertyName, value); + } + + /// + /// Checks if the custom comment source value used to decorate comments created by this addin + /// has a specific value. + /// + /// Thread to check. + /// Value to check for. + /// True if the value is identical, False otherwise. + public static bool IsCommentSource(this AzureDevOpsPullRequestCommentThread thread, string value) + { + thread.NotNull(nameof(thread)); + + return thread.GetCommentSource() == value; + } + + /// + /// Gets the comment identifier to identify the issue for which the comment was created. + /// + /// Thread to get the value from. + /// Comment identifier value. + public static string GetCommentIdentifier(this AzureDevOpsPullRequestCommentThread thread) + { + thread.NotNull(nameof(thread)); + + return thread.GetValue(CommentIdentifierPropertyName); + } + + /// + /// Sets the comment identifier value used to identify the issue for which the comment was created. + /// + /// Thread for which the value should be set. + /// Value to set as comment identifier. + public static void SetCommentIdentifier(this AzureDevOpsPullRequestCommentThread thread, string value) + { + thread.NotNull(nameof(thread)); + + thread.SetValue(CommentIdentifierPropertyName, value); + } + + /// + /// Gets the original message of the issue as provided by Cake.Issues.PullRequests, + /// without any formatting done by this addin. + /// + /// Thread to get the value from. + /// Original message of the issue. + public static string GetIssueMessage(this AzureDevOpsPullRequestCommentThread thread) + { + thread.NotNull(nameof(thread)); + + return thread.GetValue(IssueMessagePropertyName); + } + + /// + /// Sets the original message of the issue as provided by Cake.Issues.PullRequests. + /// + /// Thread for which the value should be set. + /// Value to set as the original message. + public static void SetIssueMessage(this AzureDevOpsPullRequestCommentThread thread, string value) + { + thread.NotNull(nameof(thread)); + + thread.SetValue(IssueMessagePropertyName, value); + } + + /// + /// Gets the provider type value used to identify specific provider origins later on when reading back existing issues. + /// + /// Thread to get the value from. + /// Comment source value. + public static string GetProviderType(this AzureDevOpsPullRequestCommentThread thread) + { + thread.NotNull(nameof(thread)); + + return thread.GetValue(ProviderTypePropertyName); + } + + /// + /// Sets the provider type value used to identify specific provider origins later on when reading back existing issues. + /// + /// Thread for which the value should be set. + /// Value to set as comment source. + public static void SetProviderType(this AzureDevOpsPullRequestCommentThread thread, string value) + { + thread.NotNull(nameof(thread)); + + thread.SetValue(ProviderTypePropertyName, value); + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/ContentProvider.cs b/src/Cake.Issues.PullRequests.AzureDevOps/ContentProvider.cs new file mode 100644 index 000000000..52bfd5b73 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/ContentProvider.cs @@ -0,0 +1,32 @@ +namespace Cake.Issues.PullRequests.AzureDevOps +{ + /// + /// Class for providing the content for a pull request comment. + /// + internal static class ContentProvider + { + /// + /// Returns the content for an issue. + /// + /// Issue for which the content should be returned. + /// Comment content for the issue. + public static string GetContent(IIssue issue) + { + var result = issue.Message(IssueCommentFormat.Markdown); + if (string.IsNullOrWhiteSpace(issue.RuleId)) + { + return result; + } + + var ruleContent = issue.RuleId; + if (issue.RuleUrl != null) + { + ruleContent = $"[{issue.RuleId}]({issue.RuleUrl})"; + } + + result = $"{ruleContent}: {result}"; + + return result; + } + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/IAzureDevOpsPullRequestSystem.cs b/src/Cake.Issues.PullRequests.AzureDevOps/IAzureDevOpsPullRequestSystem.cs new file mode 100644 index 000000000..2aae084f4 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/IAzureDevOpsPullRequestSystem.cs @@ -0,0 +1,23 @@ +namespace Cake.Issues.PullRequests.AzureDevOps +{ + using Cake.AzureDevOps.Repos.PullRequest; + + /// + /// Interface for writing issues to Azure DevOps pull requests. + /// + internal interface IAzureDevOpsPullRequestSystem : IPullRequestSystem + { + /// + /// Gets information about the pull request. + /// + AzureDevOpsPullRequest AzureDevOpsPullRequest { get; } + + /// + /// Validates if a pull request could be found. + /// Depending on + /// the pull request instance can be null for subsequent calls. + /// + /// True if a valid pull request instance exists. + bool ValidatePullRequest(); + } +} diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/app.config b/src/Cake.Issues.PullRequests.AzureDevOps/app.config new file mode 100644 index 000000000..46e3425f0 --- /dev/null +++ b/src/Cake.Issues.PullRequests.AzureDevOps/app.config @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.AzureDevOps/icon.png b/src/Cake.Issues.PullRequests.AzureDevOps/icon.png new file mode 100644 index 000000000..84c2a823c Binary files /dev/null and b/src/Cake.Issues.PullRequests.AzureDevOps/icon.png differ diff --git a/src/Cake.Issues.PullRequests.GitHubActions.Tests/Cake.Issues.PullRequests.GitHubActions.Tests.csproj b/src/Cake.Issues.PullRequests.GitHubActions.Tests/Cake.Issues.PullRequests.GitHubActions.Tests.csproj new file mode 100644 index 000000000..62e6abb40 --- /dev/null +++ b/src/Cake.Issues.PullRequests.GitHubActions.Tests/Cake.Issues.PullRequests.GitHubActions.Tests.csproj @@ -0,0 +1,37 @@ + + + + net6.0 + false + Tests for the Cake.Issues.PullRequests.GitHubActions addin + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.GitHubActions.Tests/GitHubActionsBuildSettingsTests.cs b/src/Cake.Issues.PullRequests.GitHubActions.Tests/GitHubActionsBuildSettingsTests.cs new file mode 100644 index 000000000..1d5d4ac42 --- /dev/null +++ b/src/Cake.Issues.PullRequests.GitHubActions.Tests/GitHubActionsBuildSettingsTests.cs @@ -0,0 +1,15 @@ +namespace Cake.Issues.PullRequests.GitHubActions.Tests +{ + using System; + using Cake.Issues.Testing; + using Cake.Testing; + using Shouldly; + using Xunit; + + public sealed class GitHubActionsBuildSettingsTests + { + public sealed class TheCtor + { + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.GitHubActions/Cake.Issues.PullRequests.GitHubActions.csproj b/src/Cake.Issues.PullRequests.GitHubActions/Cake.Issues.PullRequests.GitHubActions.csproj new file mode 100644 index 000000000..382066ef8 --- /dev/null +++ b/src/Cake.Issues.PullRequests.GitHubActions/Cake.Issues.PullRequests.GitHubActions.csproj @@ -0,0 +1,35 @@ + + + + net6.0;net7.0;net8.0 + Addin for writing code analyzer or linter issues to GitHub Actions + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + bin\$(Configuration)\$(TargetFramework)\Cake.Issues.PullRequests.GitHubActions.xml + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildSettings.cs b/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildSettings.cs new file mode 100644 index 000000000..beb2aedef --- /dev/null +++ b/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildSettings.cs @@ -0,0 +1,14 @@ +namespace Cake.Issues.PullRequests.GitHubActions +{ + /// + /// Settings for . + /// + public class GitHubActionsBuildSettings + { + /// + /// Gets or sets a value indicating whether issues should be grouped by issue provider and run information. + /// Enabled by default. + /// + public bool GroupIssues { get; set; } = true; + } +} \ No newline at end of file diff --git a/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildsAliases.cs b/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildsAliases.cs new file mode 100644 index 000000000..811f1fa47 --- /dev/null +++ b/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsBuildsAliases.cs @@ -0,0 +1,76 @@ +namespace Cake.Issues.PullRequests.GitHubActions +{ + using Cake.Core; + using Cake.Core.Annotations; + + /// + /// Contains functionality related to writing code analysis issues to GitHub Actions. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class GitHubActionsBuildsAliases + { + /// + /// Gets an object for writing issues to GitHub Actions using the default settings. + /// + /// The context. + /// Object for writing issues to GitHub Actions. + /// + /// Report code analysis issues reported as MsBuild warnings to GitHub Actions: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem GitHubActionsBuilds( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return new GitHubActionsPullRequestSystem(context, new GitHubActionsBuildSettings()); + } + + /// + /// Gets an object for writing issues to GitHub Actions using the specified settings. + /// + /// The context. + /// Settings for writing issues to GitHub Actions. + /// Object for writing issues to GitHub Actions. + /// + /// Report code analysis issues reported as MsBuild warnings to GitHub Actions: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(PullRequestsAliasConstants.PullRequestSystemCakeAliasCategory)] + public static IPullRequestSystem GitHubActionsBuilds( + this ICakeContext context, + GitHubActionsBuildSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new GitHubActionsPullRequestSystem(context, settings); + } + } +} diff --git a/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsPullRequestSystem.cs b/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsPullRequestSystem.cs new file mode 100644 index 000000000..25be50a48 --- /dev/null +++ b/src/Cake.Issues.PullRequests.GitHubActions/GitHubActionsPullRequestSystem.cs @@ -0,0 +1,124 @@ +namespace Cake.Issues.PullRequests.GitHubActions +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Cake.Core; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + + /// + /// Class for posting issues to GitHub Actions. + /// + public class GitHubActionsPullRequestSystem : BasePullRequestSystem + { + private static readonly char[] Separator = ['\n']; + private readonly GitHubActionsBuildSettings settings; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake context. + /// Settings for writing the issues to GitHub Actions. + public GitHubActionsPullRequestSystem(ICakeContext context, GitHubActionsBuildSettings settings) + : base(context?.Log) + { + settings.NotNull(nameof(settings)); + + this.settings = settings; + } + + /// + protected override void InternalPostDiscussionThreads(IEnumerable issues, string commentSource) + { + issues.NotNull(nameof(issues)); + + if (this.settings.GroupIssues) + { + this.WriteGroupedIssues(issues); + } + else + { + this.WriteIssues(issues); + } + } + + /// + /// Formats the options for the warning service message. + /// + /// The root path of the file, relative to the repository root. + /// The file path relative to the project root. + /// The line where the issue ocurred. + /// The column where the issue ocurred. + /// Formatted options string for the warning service message. + private static string FormatWarningOptions(DirectoryPath rootDirectoryPath, FilePath filePath, int? line, int? column) + { + var result = new List(); + + if (filePath != null) + { + result.Add($"file={rootDirectoryPath.CombineWithFilePath(filePath)}"); + } + + if (line.HasValue) + { + result.Add($"line={line.Value}"); + } + + if (column.HasValue) + { + result.Add($"col={column}"); + } + + return string.Join(",", result); + } + + /// + /// Writes services messages to report issues to GitHub Actions grouped by provider and run. + /// + /// Issues which should be reported. + private void WriteGroupedIssues(IEnumerable issues) + { + // Group annotations by provider type and run + var groupedIssues = + from issue in issues + group issue by new { issue.ProviderType, issue.Run }; + + foreach (var group in groupedIssues) + { + var groupName = group.First().ProviderName; + + if (!string.IsNullOrWhiteSpace(group.Key.Run)) + { + groupName += " - " + group.Key.Run; + } + + this.Log.Information($"::group::{groupName}"); + + this.WriteIssues(group); + + this.Log.Information($"::endgroup::{groupName}"); + } + } + + /// + /// Writes services message to report issues to GitHub Actions. + /// + /// Issues which should be reported. + private void WriteIssues(IEnumerable issues) + { + foreach (var issue in issues.OrderByDescending(x => x.Priority)) + { + // Commands don't support line breaks, therefore we only use the first line of the message. + var message = + issue.MessageText + .Split(Separator, StringSplitOptions.RemoveEmptyEntries) + .FirstOrDefault() + ?.Trim(); + + this.Log.Information( + $"::warning {FormatWarningOptions(this.Settings.RepositoryRoot, issue.AffectedFileRelativePath, issue.Line, issue.Column)}::{message}"); + } + } + } +} diff --git a/src/Cake.Issues.PullRequests.Tests/Cake.Issues.PullRequests.Tests.csproj b/src/Cake.Issues.PullRequests.Tests/Cake.Issues.PullRequests.Tests.csproj index df59700ce..55444d17c 100644 --- a/src/Cake.Issues.PullRequests.Tests/Cake.Issues.PullRequests.Tests.csproj +++ b/src/Cake.Issues.PullRequests.Tests/Cake.Issues.PullRequests.Tests.csproj @@ -17,8 +17,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/Cake.Issues.PullRequests/BaseCheckingCommitIdCapability.cs b/src/Cake.Issues.PullRequests/BaseCheckingCommitIdCapability.cs index 8f475ad35..10cdab926 100644 --- a/src/Cake.Issues.PullRequests/BaseCheckingCommitIdCapability.cs +++ b/src/Cake.Issues.PullRequests/BaseCheckingCommitIdCapability.cs @@ -6,20 +6,12 @@ /// Capability to post issues only if pull request is for a specific commit. /// /// Type of the pull request system to which this capability belongs. - public abstract class BaseCheckingCommitIdCapability - : BasePullRequestSystemCapability, ISupportCheckingCommitId + /// The Cake log context. + /// Pull request system to which this capability belongs. + public abstract class BaseCheckingCommitIdCapability(ICakeLog log, T pullRequestSystem) + : BasePullRequestSystemCapability(log, pullRequestSystem), ISupportCheckingCommitId where T : class, IPullRequestSystem { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - /// Pull request system to which this capability belongs. - protected BaseCheckingCommitIdCapability(ICakeLog log, T pullRequestSystem) - : base(log, pullRequestSystem) - { - } - /// public abstract string GetLastSourceCommitId(); } diff --git a/src/Cake.Issues.PullRequests/BaseDiscussionThreadsCapability.cs b/src/Cake.Issues.PullRequests/BaseDiscussionThreadsCapability.cs index 52f9090c0..3b9194197 100644 --- a/src/Cake.Issues.PullRequests/BaseDiscussionThreadsCapability.cs +++ b/src/Cake.Issues.PullRequests/BaseDiscussionThreadsCapability.cs @@ -7,20 +7,12 @@ /// Capability to read, resolve and reopen discussion threads. /// /// Type of the pull request system to which this capability belongs. - public abstract class BaseDiscussionThreadsCapability - : BasePullRequestSystemCapability, ISupportDiscussionThreads + /// The Cake log context. + /// Pull request system to which this capability belongs. + public abstract class BaseDiscussionThreadsCapability(ICakeLog log, T pullRequestSystem) + : BasePullRequestSystemCapability(log, pullRequestSystem), ISupportDiscussionThreads where T : class, IPullRequestSystem { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - /// Pull request system to which this capability belongs. - protected BaseDiscussionThreadsCapability(ICakeLog log, T pullRequestSystem) - : base(log, pullRequestSystem) - { - } - /// public IEnumerable FetchDiscussionThreads(string commentSource) { diff --git a/src/Cake.Issues.PullRequests/BaseFilteringByModifiedFilesCapability.cs b/src/Cake.Issues.PullRequests/BaseFilteringByModifiedFilesCapability.cs index f2b24a4df..d0f80c0c9 100644 --- a/src/Cake.Issues.PullRequests/BaseFilteringByModifiedFilesCapability.cs +++ b/src/Cake.Issues.PullRequests/BaseFilteringByModifiedFilesCapability.cs @@ -8,20 +8,12 @@ /// Capability to filter issues to only those affecting files modified in the pull request. /// /// Type of the pull request system to which this capability belongs. - public abstract class BaseFilteringByModifiedFilesCapability - : BasePullRequestSystemCapability, ISupportFilteringByModifiedFiles + /// The Cake log context. + /// Pull request system to which this capability belongs. + public abstract class BaseFilteringByModifiedFilesCapability(ICakeLog log, T pullRequestSystem) + : BasePullRequestSystemCapability(log, pullRequestSystem), ISupportFilteringByModifiedFiles where T : class, IPullRequestSystem { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - /// Pull request system to which this capability belongs. - protected BaseFilteringByModifiedFilesCapability(ICakeLog log, T pullRequestSystem) - : base(log, pullRequestSystem) - { - } - /// public IEnumerable GetModifiedFilesInPullRequest() { diff --git a/src/Cake.Issues.PullRequests/BasePullRequestSystem.cs b/src/Cake.Issues.PullRequests/BasePullRequestSystem.cs index 357e96a1d..1e25810b1 100644 --- a/src/Cake.Issues.PullRequests/BasePullRequestSystem.cs +++ b/src/Cake.Issues.PullRequests/BasePullRequestSystem.cs @@ -7,20 +7,12 @@ /// /// Base class for all pull request system implementations. /// - public abstract class BasePullRequestSystem - : BaseIssueComponent, IPullRequestSystem + /// The Cake log context. + public abstract class BasePullRequestSystem(ICakeLog log) + : BaseIssueComponent(log), IPullRequestSystem { private readonly List capabilities = []; - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - protected BasePullRequestSystem(ICakeLog log) - : base(log) - { - } - /// public void AddCapability(IPullRequestSystemCapability capability) { diff --git a/src/Cake.Issues.Reporting.Console.Tests/Cake.Issues.Reporting.Console.Tests.csproj b/src/Cake.Issues.Reporting.Console.Tests/Cake.Issues.Reporting.Console.Tests.csproj new file mode 100644 index 000000000..7c11008c3 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console.Tests/Cake.Issues.Reporting.Console.Tests.csproj @@ -0,0 +1,56 @@ + + + + Library + net6.0 + false + Tests for the Cake.Issues.Reporting.Console addin + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + ..\Cake.Issues.Tests.ruleset + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + + + + + + 4.0.0 + + + 4.2.1 + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + 2.7.1 + + + 2.5.8 + runtime; build; native; contentfiles; analyzers + all + + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Console.Tests/ConsoleIssueReportFixture.cs b/src/Cake.Issues.Reporting.Console.Tests/ConsoleIssueReportFixture.cs new file mode 100644 index 000000000..f53f654fd --- /dev/null +++ b/src/Cake.Issues.Reporting.Console.Tests/ConsoleIssueReportFixture.cs @@ -0,0 +1,83 @@ +namespace Cake.Issues.Reporting.Console.Tests +{ + using System; + using System.Collections.Generic; + using System.IO; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Cake.Issues.Serialization; + using Cake.Testing; + using Shouldly; + + internal class ConsoleIssueReportFixture + { + public ConsoleIssueReportFixture() + { + this.Log = new FakeLog { Verbosity = Verbosity.Normal }; + this.ConsoleIssueReportFormatSettings = new ConsoleIssueReportFormatSettings(); + } + + public FakeLog Log { get; set; } + + public ConsoleIssueReportFormatSettings ConsoleIssueReportFormatSettings { get; set; } + + public string CreateReport(string fileResourceName, DirectoryPath repositoryRootPath) + { + fileResourceName.NotNullOrWhiteSpace(nameof(fileResourceName)); + + var resourceName = "Cake.Issues.Reporting.Console.Tests." + fileResourceName; + + using (var stream = this.GetType().Assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { + if (stream == null) + { + throw new ArgumentException( + $"Resource {resourceName} not found", + nameof(fileResourceName)); + } + + var issues = IssueDeserializationExtensions.DeserializeToIssues(reader.ReadToEnd()); + return this.CreateReport(issues, repositoryRootPath); + } + } + + public string CreateReport(IEnumerable issues, DirectoryPath repositoryRootPath) + { + var generator = + new ConsoleIssueReportGenerator(this.Log, this.ConsoleIssueReportFormatSettings); + + var createIssueReportSettings = + new CreateIssueReportSettings(repositoryRootPath, string.Empty); + generator.Initialize(createIssueReportSettings); + generator.CreateReport(issues); + + // TODO Return console output + return string.Empty; + } + + public void TestReportCreation(Action settings) + { + // Given + settings(this.ConsoleIssueReportFormatSettings); + + // When + var result = + this.CreateReport( + new List + { + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 10) + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Warning) + .Create(), + }, + @"c:\Source\Cake.Issues.Reporting.Console"); + + // Then + // Currently only checks if generation failed or not without checking actual output. + result.ShouldNotBeNull(); + } + } +} diff --git a/src/Cake.Issues.Reporting.Console.Tests/ConsoleIssueReportGeneratorTests.cs b/src/Cake.Issues.Reporting.Console.Tests/ConsoleIssueReportGeneratorTests.cs new file mode 100644 index 000000000..d4c5207ec --- /dev/null +++ b/src/Cake.Issues.Reporting.Console.Tests/ConsoleIssueReportGeneratorTests.cs @@ -0,0 +1,103 @@ +namespace Cake.Issues.Reporting.Console.Tests +{ + using System.Collections.Generic; + using System.Linq; + using Cake.Issues.Testing; + using Cake.Testing; + using Xunit; + + public sealed class ConsoleIssueReportGeneratorTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => + new ConsoleIssueReportGenerator( + null, + new ConsoleIssueReportFormatSettings())); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given / When + var result = Record.Exception(() => + new ConsoleIssueReportGenerator( + new FakeLog(), + null)); + + // Then + result.IsArgumentNullException("settings"); + } + } + + public sealed class TheInternalCreateReportMethod + { + public static IEnumerable ReportFormatSettingsCombinations => + from b1 in new[] { false, true } + from b2 in new[] { false, true } + from b3 in new[] { false, true } + from b4 in new[] { false, true } + from b5 in new[] { false, true } + select new object[] { b1, b2, b3, b4, b5 }; + + [Theory] + [MemberData(nameof(ReportFormatSettingsCombinations))] + public void Should_Generate_Report( + bool showDiagnostics, + bool compact, + bool groupByRule, + bool showProviderSummary, + bool showPrioritySummary) + { + // Given + var fixture = new ConsoleIssueReportFixture(); + fixture.ConsoleIssueReportFormatSettings.ShowDiagnostics = showDiagnostics; + fixture.ConsoleIssueReportFormatSettings.Compact = compact; + fixture.ConsoleIssueReportFormatSettings.GroupByRule = groupByRule; + fixture.ConsoleIssueReportFormatSettings.ShowProviderSummary = showProviderSummary; + fixture.ConsoleIssueReportFormatSettings.ShowPrioritySummary = showPrioritySummary; + + // When + var logContents = + fixture.CreateReport( + "Testfiles.issues.json", + @"c:\Source\Cake.Issues.Reporting.Console"); + + // Then + } + + [Theory] + [MemberData(nameof(ReportFormatSettingsCombinations))] + public void Should_Generate_Report_With_No_Issues( + bool showDiagnostics, + bool compact, + bool groupByRule, + bool showProviderSummary, + bool showPrioritySummary) + { + // Given + var fixture = new ConsoleIssueReportFixture(); + fixture.ConsoleIssueReportFormatSettings.ShowDiagnostics = showDiagnostics; + fixture.ConsoleIssueReportFormatSettings.Compact = compact; + fixture.ConsoleIssueReportFormatSettings.GroupByRule = groupByRule; + fixture.ConsoleIssueReportFormatSettings.ShowProviderSummary = showProviderSummary; + fixture.ConsoleIssueReportFormatSettings.ShowPrioritySummary = showPrioritySummary; + + // When + var logContents = + fixture.CreateReport( + new List(), + @"c:\Source\Cake.Issues.Reporting.Console"); + + // Then + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Console.Tests/Properties/SolutionInfo.cs b/src/Cake.Issues.Reporting.Console.Tests/Properties/SolutionInfo.cs new file mode 100644 index 000000000..3b34026e7 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console.Tests/Properties/SolutionInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a6ec509d-8ddc-4ec8-ba7e-a173f48e61fa")] diff --git a/src/Cake.Issues.Reporting.Console.Tests/Testfiles/issues.json b/src/Cake.Issues.Reporting.Console.Tests/Testfiles/issues.json new file mode 100644 index 000000000..6b50b61c4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console.Tests/Testfiles/issues.json @@ -0,0 +1 @@ +[{"Version":4,"Identifier":"The file header is missing or not located at the top of the file.","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":1,"EndLine":null,"Column":1,"EndColumn":null,"FileLink":null,"MessageText":"The file header is missing or not located at the top of the file.","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA1633","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1633.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive should appear within a namespace declaration","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":1,"EndLine":null,"Column":1,"EndColumn":null,"FileLink":null,"MessageText":"Using directive should appear within a namespace declaration","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA1200","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive should appear within a namespace declaration","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":2,"EndLine":null,"Column":1,"EndColumn":null,"FileLink":null,"MessageText":"Using directive should appear within a namespace declaration","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA1200","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive should appear within a namespace declaration","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":3,"EndLine":null,"Column":1,"EndColumn":null,"FileLink":null,"MessageText":"Using directive should appear within a namespace declaration","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA1200","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive should appear within a namespace declaration","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":4,"EndLine":null,"Column":1,"EndColumn":null,"FileLink":null,"MessageText":"Using directive should appear within a namespace declaration","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA1200","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive should appear within a namespace declaration","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":5,"EndLine":null,"Column":1,"EndColumn":null,"FileLink":null,"MessageText":"Using directive should appear within a namespace declaration","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA1200","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Member 'Foo' does not access instance data and can be marked as static","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":11,"EndLine":null,"Column":21,"EndColumn":null,"FileLink":null,"MessageText":"Member 'Foo' does not access instance data and can be marked as static","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"CA1822","RuleUrl":"https://www.google.com/search?q=\"CA1822:\"+site:docs.microsoft.com","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Member 'Bar' does not access instance data and can be marked as static","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":21,"EndLine":null,"Column":21,"EndColumn":null,"FileLink":null,"MessageText":"Member 'Bar' does not access instance data and can be marked as static","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"CA1822","RuleUrl":"https://www.google.com/search?q=\"CA1822:\"+site:docs.microsoft.com","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"XML comment analysis is disabled due to project configuration","ProjectFileRelativePath":"src/ClassLibrary1/ClassLibrary1.csproj","ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/CSC","Line":null,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"XML comment analysis is disabled due to project configuration","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"SA0001","RuleUrl":"https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA0001.md","ProviderType":"Cake.Issues.MsBuild.MsBuildIssuesProvider","ProviderName":"MSBuild","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive is not required by the code and can be safely removed","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":1,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Using directive is not required by the code and can be safely removed","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"RedundantUsingDirective","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirective","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive is not required by the code and can be safely removed","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":2,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Using directive is not required by the code and can be safely removed","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"RedundantUsingDirective","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirective","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive is not required by the code and can be safely removed","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":3,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Using directive is not required by the code and can be safely removed","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"RedundantUsingDirective","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirective","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive is not required by the code and can be safely removed","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":4,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Using directive is not required by the code and can be safely removed","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"RedundantUsingDirective","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirective","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Using directive is not required by the code and can be safely removed","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":5,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Using directive is not required by the code and can be safely removed","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"RedundantUsingDirective","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=RedundantUsingDirective","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Class 'Class1' is never used","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":9,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Class 'Class1' is never used","MessageMarkdown":null,"MessageHtml":null,"Priority":200,"PriorityName":"Suggestion","Rule":"UnusedType.Global","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=UnusedType.Global","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Method 'Foo' is never used","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":11,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Method 'Foo' is never used","MessageMarkdown":null,"MessageHtml":null,"Priority":200,"PriorityName":"Suggestion","Rule":"UnusedMember.Global","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=UnusedMember.Global","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Local variable 'foobar' is never used","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":17,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Local variable 'foobar' is never used","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"UnusedVariable","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=UnusedVariable","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Method 'Bar' is never used","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":21,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Method 'Bar' is never used","MessageMarkdown":null,"MessageHtml":null,"Priority":200,"PriorityName":"Suggestion","Rule":"UnusedMember.Global","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=UnusedMember.Global","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Local variable 'foobar' is never used","ProjectFileRelativePath":null,"ProjectName":"ClassLibrary1","AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":27,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Local variable 'foobar' is never used","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"UnusedVariable","RuleUrl":"https://www.jetbrains.com/resharperplatform/help?Keyword=UnusedVariable","ProviderType":"Cake.Issues.InspectCode.InspectCodeIssuesProvider","ProviderName":"InspectCode","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"src\\ClassLibrary1\\Class1.cs-76-src\\ClassLibrary1\\Class1.cs","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":12,"EndLine":19,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Possible duplicate detected (cost 76).\r\nThe following fragments were found that might be duplicates:\r\n\"src\\ClassLibrary1\\Class1.cs\" (Line 22 to 29)","MessageMarkdown":"Possible duplicate detected (cost 76).\r\nThe following fragments were found that might be duplicates:\r\n`src\\ClassLibrary1\\Class1.cs` (Line 22 to 29)","MessageHtml":"Possible duplicate detected (cost 76).
The following fragments were found that might be duplicates:
src\\ClassLibrary1\\Class1.cs (Line 22 to 29)","Priority":300,"PriorityName":"Warning","Rule":"dupFinder","RuleUrl":null,"ProviderType":"Cake.Issues.DupFinder.DupFinderIssuesProvider","ProviderName":"DupFinder","Run":null,"AdditionalInformation":{"cost":"76"}},{"Version":4,"Identifier":"src\\ClassLibrary1\\Class1.cs-76-src\\ClassLibrary1\\Class1.cs","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"src/ClassLibrary1/Class1.cs","Line":22,"EndLine":29,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Possible duplicate detected (cost 76).\r\nThe following fragments were found that might be duplicates:\r\n\"src\\ClassLibrary1\\Class1.cs\" (Line 12 to 19)","MessageMarkdown":"Possible duplicate detected (cost 76).\r\nThe following fragments were found that might be duplicates:\r\n`src\\ClassLibrary1\\Class1.cs` (Line 12 to 19)","MessageHtml":"Possible duplicate detected (cost 76).
The following fragments were found that might be duplicates:
src\\ClassLibrary1\\Class1.cs (Line 12 to 19)","Priority":300,"PriorityName":"Warning","Rule":"dupFinder","RuleUrl":null,"ProviderType":"Cake.Issues.DupFinder.DupFinderIssuesProvider","ProviderName":"DupFinder","Run":null,"AdditionalInformation":{"cost":"76"}},{"Version":4,"Identifier":"Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: \"# foo\"]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":1,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: \"# foo\"]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD022","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md022","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Trailing spaces [Expected: 0 or 2; Actual: 1]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":2,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Trailing spaces [Expected: 0 or 2; Actual: 1]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD009","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md009","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Line length [Expected: 80; Actual: 811]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":2,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Line length [Expected: 80; Actual: 811]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD013","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md013","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: \"# bar\"]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":4,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: \"# bar\"]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD022","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md022","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Multiple top-level headings in the same document [Context: \"# bar\"]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":4,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Multiple top-level headings in the same document [Context: \"# bar\"]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD025","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md025","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Fenced code blocks should be surrounded by blank lines [Context: \"```\"]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":5,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Fenced code blocks should be surrounded by blank lines [Context: \"```\"]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD031","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md031","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Fenced code blocks should have a language specified [Context: \"```\"]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":5,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Fenced code blocks should have a language specified [Context: \"```\"]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD040","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md040","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Line length [Expected: 80; Actual: 840]","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":6,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Line length [Expected: 80; Actual: 840]","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD013","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md013","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}},{"Version":4,"Identifier":"Files should end with a single newline character","ProjectFileRelativePath":null,"ProjectName":null,"AffectedFileRelativePath":"docs/index.md","Line":7,"EndLine":null,"Column":null,"EndColumn":null,"FileLink":null,"MessageText":"Files should end with a single newline character","MessageMarkdown":null,"MessageHtml":null,"Priority":300,"PriorityName":"Warning","Rule":"MD047","RuleUrl":"https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md047","ProviderType":"Cake.Issues.Markdownlint.MarkdownlintIssuesProvider","ProviderName":"markdownlint","Run":null,"AdditionalInformation":{}}] \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Console/Cake.Issues.Reporting.Console.csproj b/src/Cake.Issues.Reporting.Console/Cake.Issues.Reporting.Console.csproj new file mode 100644 index 000000000..f89d95700 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/Cake.Issues.Reporting.Console.csproj @@ -0,0 +1,48 @@ + + + + Library + net6.0;net7.0;net8.0 + Support for reporting issues to the console for the Cake.Issues addin for Cake Build Automation System + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + latest + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + true + + + + bin\Debug\Cake.Issues.Reporting.Console.xml + DEBUG;TRACE + + + + bin\Release\Cake.Issues.Reporting.Console.xml + TRACE + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/src/Cake.Issues.Reporting.Console/ConsoleIssueReportFormatAliases.cs b/src/Cake.Issues.Reporting.Console/ConsoleIssueReportFormatAliases.cs new file mode 100644 index 000000000..b629081c4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/ConsoleIssueReportFormatAliases.cs @@ -0,0 +1,76 @@ +namespace Cake.Issues.Reporting.Console +{ + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Issues.Reporting; + + /// + /// Contains functionality to report issues to the console. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class ConsoleIssueReportFormatAliases + { + /// + /// Gets an instance of the console report format using default settings. + /// + /// The context. + /// Instance of a console report format. + /// + /// Report issues to console: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat ConsoleIssueReportFormat( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return context.ConsoleIssueReportFormat(new ConsoleIssueReportFormatSettings()); + } + + /// + /// Gets an instance of the console report format using specified settings. + /// + /// The context. + /// Settings for generating the report. + /// Instance of a console report format. + /// + /// Report issues to console grouped by rule: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat ConsoleIssueReportFormat( + this ICakeContext context, + ConsoleIssueReportFormatSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new ConsoleIssueReportGenerator(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.Reporting.Console/ConsoleIssueReportFormatSettings.cs b/src/Cake.Issues.Reporting.Console/ConsoleIssueReportFormatSettings.cs new file mode 100644 index 000000000..35d4c4748 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/ConsoleIssueReportFormatSettings.cs @@ -0,0 +1,38 @@ +namespace Cake.Issues.Reporting.Console +{ + /// + /// Settings for . + /// + public class ConsoleIssueReportFormatSettings + { + /// + /// Gets or sets a value indicating whether diagnostics for the individual issues should be shown. + /// Default value is true. + /// + public bool ShowDiagnostics { get; set; } = true; + + /// + /// Gets or sets a value indicating whether or not the report should be rendered in compact mode. + /// Default value is false. + /// + public bool Compact { get; set; } + + /// + /// Gets or sets a value indicating whether issues should be grouped by rule or if + /// for every issue a separate diagnostic should be created. + /// + public bool GroupByRule { get; set; } + + /// + /// Gets or sets a value indicating whether a summary of issues by provider / run + /// should be shown. + /// + public bool ShowProviderSummary { get; set; } + + /// + /// Gets or sets a value indicating whether a summary of issues by provider / run + /// with the number of issues for each priority should be shown. + /// + public bool ShowPrioritySummary { get; set; } + } +} diff --git a/src/Cake.Issues.Reporting.Console/ConsoleIssueReportGenerator.cs b/src/Cake.Issues.Reporting.Console/ConsoleIssueReportGenerator.cs new file mode 100644 index 000000000..ccd2896e0 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/ConsoleIssueReportGenerator.cs @@ -0,0 +1,167 @@ +namespace Cake.Issues.Reporting.Console +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Errata; + using Spectre.Console; + + /// + /// Generator for reporting issues to console. + /// + internal class ConsoleIssueReportGenerator : IssueReportFormat + { + private readonly ConsoleIssueReportFormatSettings consoleIssueReportFormatSettings; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake log context. + /// Settings for reporting the issues. + public ConsoleIssueReportGenerator(ICakeLog log, ConsoleIssueReportFormatSettings settings) + : base(log) + { + settings.NotNull(nameof(settings)); + + this.consoleIssueReportFormatSettings = settings; + } + + /// + protected override FilePath InternalCreateReport(IEnumerable issues) + { + var enumeratedIssues = issues.ToList(); + if (this.consoleIssueReportFormatSettings.ShowProviderSummary) + { + // Filter to issues from existing files + var diagnosticIssues = + enumeratedIssues + .Where(x => + x.AffectedFileRelativePath != null && + File.Exists(this.Settings.RepositoryRoot.CombineWithFilePath(x.AffectedFileRelativePath).FullPath)) + .ToList(); + + // Filter to issues with line and column information + // Errata currently doesn't support file or line level diagnostics. + // https://github.com/cake-contrib/Cake.Issues.Reporting.Console/issues/4 + // https://github.com/cake-contrib/Cake.Issues.Reporting.Console/issues/5 + diagnosticIssues = + diagnosticIssues + .Where(x => x.Line.HasValue && x.Column.HasValue) + .ToList(); + + var report = new Report(new FileSystemRepository(this.Settings)); + + if (this.consoleIssueReportFormatSettings.GroupByRule) + { + foreach (var issueGroup in diagnosticIssues.GroupBy(x => x.RuleId)) + { + report.AddDiagnostic(new IssueDiagnostic(issueGroup)); + } + } + else + { + foreach (var issue in diagnosticIssues) + { + report.AddDiagnostic(new IssueDiagnostic(issue)); + } + } + + report.Render( + AnsiConsole.Console, + new ReportSettings + { + Compact = this.consoleIssueReportFormatSettings.Compact, + }); + } + + if (this.consoleIssueReportFormatSettings.ShowProviderSummary || this.consoleIssueReportFormatSettings.ShowPrioritySummary) + { + this.PrintSummary(enumeratedIssues); + } + + return null; + } + + /// + /// Prints the issues of issues. + /// + /// List of issues. + private void PrintSummary(IList issues) + { + if (!issues.Any()) + { + AnsiConsole.WriteLine("No issues"); + return; + } + + AnsiConsole.WriteLine(); + AnsiConsole.WriteLine(); + var rule = new Rule("Summary").Centered(); + AnsiConsole.Write(rule); + AnsiConsole.WriteLine(); + + var providerChart = new BarChart(); + + var priorityTable = new Table + { + Border = TableBorder.Rounded, + Expand = true, + }; + priorityTable.AddColumn(new TableColumn("Issue Provider / Run").Centered()); + priorityTable.AddColumn(new TableColumn("Number Of Issues").Centered()); + + var i = 1; + foreach (var providerGroup in issues.GroupBy(x => x.ProviderName)) + { + var issueProvider = providerGroup.Key; + + providerChart.AddItem(issueProvider, providerGroup.Count(), Color.FromInt32(i)); + + foreach (var runGroup in providerGroup.GroupBy(x => x.Run)) + { + if (!string.IsNullOrEmpty(runGroup.Key)) + { + issueProvider += " / {runGroup.Key}"; + } + + var errorCount = runGroup.Count(x => x.Priority.HasValue && x.Priority.Value == (int)IssuePriority.Error); + var warningCount = runGroup.Count(x => x.Priority.HasValue && x.Priority.Value == (int)IssuePriority.Warning); + var hintCount = runGroup.Count(x => x.Priority.HasValue && x.Priority.Value == (int)IssuePriority.Hint); + var suggestionCount = runGroup.Count(x => x.Priority.HasValue && x.Priority.Value == (int)IssuePriority.Suggestion); + var unknownCount = runGroup.Count(x => !x.Priority.HasValue || x.Priority.Value == (int)IssuePriority.Undefined); + + var chart = + new BarChart() + .AddItem("Errors", errorCount, Color.Red) + .AddItem("Warnings", warningCount, Color.Yellow) + .AddItem("Hint", hintCount, Color.LightSkyBlue1) + .AddItem("Suggestion", suggestionCount, Color.Green) + .AddItem("Unknown", unknownCount, Color.DarkSlateGray1); + + priorityTable.AddRow(new Markup(issueProvider), chart); + } + + priorityTable.AddEmptyRow(); + i++; + } + + if (this.consoleIssueReportFormatSettings.ShowProviderSummary) + { + AnsiConsole.Write(new Markup("[bold]Issues per provider & run[/]").Centered()); + AnsiConsole.WriteLine(); + AnsiConsole.WriteLine(); + AnsiConsole.Write(providerChart); + AnsiConsole.WriteLine(); + } + + if (this.consoleIssueReportFormatSettings.ShowPrioritySummary) + { + AnsiConsole.Write(new Markup("[bold]Issues per priority[/]").Centered()); + AnsiConsole.WriteLine(); + AnsiConsole.Write(priorityTable); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Console/FileSystemRepository.cs b/src/Cake.Issues.Reporting.Console/FileSystemRepository.cs new file mode 100644 index 000000000..9249647c5 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/FileSystemRepository.cs @@ -0,0 +1,36 @@ +namespace Cake.Issues.Reporting.Console +{ + using System; + using System.Collections.Generic; + using System.IO; + using Errata; + + /// + /// Repository to read the source files from the file system. + /// + /// Settings for report creation. + internal sealed class FileSystemRepository(ICreateIssueReportSettings settings) : ISourceRepository + { + private readonly ICreateIssueReportSettings settings = settings; + private readonly Dictionary cache = new(StringComparer.OrdinalIgnoreCase); + + /// + public bool TryGet(string id, out Source source) + { + if (!this.cache.TryGetValue(id, out source)) + { + var filePath = this.settings.RepositoryRoot.Combine(id).FullPath; + + if (!File.Exists(filePath)) + { + return false; + } + + source = new Source(id, File.ReadAllText(filePath)); + this.cache[id] = source; + } + + return true; + } + } +} diff --git a/src/Cake.Issues.Reporting.Console/IssueDiagnostic.cs b/src/Cake.Issues.Reporting.Console/IssueDiagnostic.cs new file mode 100644 index 000000000..cc30e8c79 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/IssueDiagnostic.cs @@ -0,0 +1,111 @@ +namespace Cake.Issues.Reporting.Console +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Errata; + using Spectre.Console; + + /// + /// Custom diagnostic for issues. + /// + internal sealed class IssueDiagnostic : Diagnostic + { + private readonly IEnumerable issues; + + /// + /// Initializes a new instance of the class. + /// + /// Issue which the diagnostic should describe. + public IssueDiagnostic(IIssue issue) + : this(new List { issue }) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Issues which the diagnostic should describe. + public IssueDiagnostic(IEnumerable issues) + : base(issues.First().RuleId) + { + this.issues = issues; + + var firstIssue = this.issues.First(); + + this.Category = firstIssue.PriorityName; + this.Color = + firstIssue.Priority switch + { + (int)IssuePriority.Error => Color.Red, + (int)IssuePriority.Warning => Color.Yellow, + (int)IssuePriority.Suggestion => Color.Blue, + (int)IssuePriority.Hint => Color.LightSkyBlue1, + _ => throw new Exception(), + }; + + if (firstIssue.RuleUrl != null) + { + this.Note = $"See {firstIssue.RuleUrl} for more information"; + } + + this.CreateLabels(); + } + + /// + /// Creates labels for the issue. + /// + private void CreateLabels() + { + var color = this.issues.First().Priority switch + { + (int)IssuePriority.Error => Color.Red, + (int)IssuePriority.Warning => Color.Yellow, + (int)IssuePriority.Suggestion or (int)IssuePriority.Hint => Color.Blue, + _ => throw new Exception(), + }; + + foreach (var issue in this.issues) + { + (var location, var length) = this.GetLocation(issue); + var label = + new Label( + issue.AffectedFileRelativePath.FullPath, + location, + issue.Message(IssueCommentFormat.PlainText)) + .WithColor(color); + + if (length > 0) + { + label = label.WithLength(length); + } + + this.Labels.Add(label); + } + } + + /// + /// Returns the diagnostic location of an issue. + /// + /// Issue for which the location should be returned. + /// Location for the diagnostic. + private (Location Location, int Lenght) GetLocation(IIssue issue) + { + // Errata currently doesn't support file or line level diagnostics. + if (!issue.Line.HasValue || !issue.Column.HasValue) + { + return default; + } + + var location = new Location(issue.Line.Value, issue.Column.Value); + + var lenght = 0; + if (issue.EndColumn.HasValue) + { + lenght = issue.EndColumn.Value - issue.Column.Value; + } + + return (location, lenght); + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Console/Properties/SolutionInfo.cs b/src/Cake.Issues.Reporting.Console/Properties/SolutionInfo.cs new file mode 100644 index 000000000..02b427c78 --- /dev/null +++ b/src/Cake.Issues.Reporting.Console/Properties/SolutionInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ed048c31-6180-4e2f-a786-207f489c37e8")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.Reporting.Console.Tests")] diff --git a/src/Cake.Issues.Reporting.Generic.Tests/Cake.Issues.Reporting.Generic.Tests.csproj b/src/Cake.Issues.Reporting.Generic.Tests/Cake.Issues.Reporting.Generic.Tests.csproj new file mode 100644 index 000000000..858b7cc5b --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/Cake.Issues.Reporting.Generic.Tests.csproj @@ -0,0 +1,60 @@ + + + + net6.0 + false + Tests for the Cake.Issues.Reporting.Generic addin + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + 1.2.0-beta.556 + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + 2.7.1 + + + 2.5.8 + + + + + + + + + + + diff --git a/src/Cake.Issues.Reporting.Generic.Tests/ColumnSortOrderExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/ColumnSortOrderExtensionsTests.cs new file mode 100644 index 000000000..8d02dc0b4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/ColumnSortOrderExtensionsTests.cs @@ -0,0 +1,28 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Diagnostics.CodeAnalysis; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class ColumnSortOrderExtensionsTests + { + public sealed class TheToShortStringMethod + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Return_Identifier(ColumnSortOrder sortOrder) + { + // Given + + // When + var result = sortOrder.ToShortString(); + + // Then + result.ShouldNotBeNullOrWhiteSpace(); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/DevExtremeThemeExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/DevExtremeThemeExtensionsTests.cs new file mode 100644 index 000000000..aaff5cd9d --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/DevExtremeThemeExtensionsTests.cs @@ -0,0 +1,37 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class DevExtremeThemeExtensionsTests + { + public sealed class TheGetCssFileNameMethod + { + public static IEnumerable DevExtremeThemes() + { + foreach (var number in Enum.GetValues(typeof(DevExtremeTheme))) + { + yield return new[] { number }; + } + } + + [Theory] + [MemberData(nameof(DevExtremeThemes))] + public void Should_Return_FileName(DevExtremeTheme theme) + { + // Given + + // When + var result = theme.GetCssFileName(); + + // Then + result.ShouldNotBeNullOrWhiteSpace(); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/ExceptionAssertExtensions.cs b/src/Cake.Issues.Reporting.Generic.Tests/ExceptionAssertExtensions.cs new file mode 100644 index 000000000..282f10df1 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/ExceptionAssertExtensions.cs @@ -0,0 +1,26 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Microsoft.CSharp.RuntimeBinder; + using Shouldly; + using Xunit; + + /// + /// Extensions for asserting exceptions. + /// + internal static class ExceptionAssertExtensions + { + /// + /// Checks if an exception is of type . + /// + /// Exception to check. + /// Expected exception message. + [SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Global", Justification = "By design for assertions")] + public static void IsRuntimeBinderException(this Exception exception, string message) + { + Assert.IsType(exception); + message.ShouldBe(exception.Message); + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/ExpandoObjectExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/ExpandoObjectExtensionsTests.cs new file mode 100644 index 000000000..e251d69d5 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/ExpandoObjectExtensionsTests.cs @@ -0,0 +1,88 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Dynamic; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class ExpandoObjectExtensionsTests + { + public sealed class TheSerializeToJsonStringExtensionForAnObject + { + [Fact] + public void Should_Throw_If_Object_Is_Null() + { + // Given + ExpandoObject expandoObject = null; + + // When + var result = Record.Exception(() => expandoObject.SerializeToJsonString()); + + // Then + result.IsArgumentNullException("expandoObject"); + } + + [Fact] + public void Should_Give_Correct_Result() + { + // Given + var issue = + IssueBuilder + .NewIssue("message", "providerType", "providerName") + .Create(); + var expandoObject = + issue.GetExpandoObject(); + + // When + var result = expandoObject.SerializeToJsonString(); + + // Then + result.ShouldBe("{\"ProviderType\":\"providerType\",\"ProviderName\":\"providerName\",\"Run\":null,\"Priority\":null,\"PriorityName\":null,\"ProjectPath\":null,\"ProjectName\":null,\"FilePath\":null,\"FileDirectory\":null,\"FileName\":null,\"FileLink\":null,\"Line\":null,\"EndLine\":null,\"Column\":null,\"EndColumn\":null,\"Location\":\"\",\"RuleId\":null,\"RuleName\":null,\"RuleUrl\":null,\"MessageText\":\"message\"}"); + } + } + + public sealed class TheSerializeToJsonStringExtensionForAnEnumerable + { + [Fact] + public void Should_Throw_If_Object_Is_Null() + { + // Given + IEnumerable expandoObjects = null; + + // When + var result = Record.Exception(() => expandoObjects.SerializeToJsonString()); + + // Then + result.IsArgumentNullException("expandoObjects"); + } + + [Fact] + public void Should_Give_Correct_Result() + { + // Given + var issue1 = + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .Create() + .GetExpandoObject(); + var issue2 = + IssueBuilder + .NewIssue("message1", "providerType1", "providerName1") + .Create() + .GetExpandoObject(); + var expandoObjects = + new List { issue1, issue2 }; + + // When + var result = expandoObjects.SerializeToJsonString(); + + // Then + result.ShouldBe("[{\"ProviderType\":\"providerType1\",\"ProviderName\":\"providerName1\",\"Run\":null,\"Priority\":null,\"PriorityName\":null,\"ProjectPath\":null,\"ProjectName\":null,\"FilePath\":null,\"FileDirectory\":null,\"FileName\":null,\"FileLink\":null,\"Line\":null,\"EndLine\":null,\"Column\":null,\"EndColumn\":null,\"Location\":\"\",\"RuleId\":null,\"RuleName\":null,\"RuleUrl\":null,\"MessageText\":\"message1\"},{\"ProviderType\":\"providerType1\",\"ProviderName\":\"providerName1\",\"Run\":null,\"Priority\":null,\"PriorityName\":null,\"ProjectPath\":null,\"ProjectName\":null,\"FilePath\":null,\"FileDirectory\":null,\"FileName\":null,\"FileLink\":null,\"Line\":null,\"EndLine\":null,\"Column\":null,\"EndColumn\":null,\"Location\":\"\",\"RuleId\":null,\"RuleName\":null,\"RuleUrl\":null,\"MessageText\":\"message1\"}]"); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFixture.cs b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFixture.cs new file mode 100644 index 000000000..764ba94dd --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFixture.cs @@ -0,0 +1,87 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Collections.Generic; + using System.IO; + using Cake.Core.Diagnostics; + using Cake.Testing; + using Shouldly; + + internal class GenericIssueReportFixture + { + public GenericIssueReportFixture(GenericIssueReportTemplate template) + { + this.Log = new FakeLog { Verbosity = Verbosity.Normal }; + this.GenericIssueReportFormatSettings = + GenericIssueReportFormatSettings.FromEmbeddedTemplate(template); + } + + public GenericIssueReportFixture(string templateContent) + { + this.Log = new FakeLog { Verbosity = Verbosity.Normal }; + this.GenericIssueReportFormatSettings = + GenericIssueReportFormatSettings.FromContent(templateContent); + } + + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public FakeLog Log { get; set; } + + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global + public GenericIssueReportFormatSettings GenericIssueReportFormatSettings { get; set; } + + public string CreateReport(IEnumerable issues) + { + var generator = + new GenericIssueReportGenerator(this.Log, this.GenericIssueReportFormatSettings); + + var reportFile = Path.GetTempFileName(); + try + { + var createIssueReportSettings = + new CreateIssueReportSettings(@"c:\Source\Cake.Issues.Reporting.Generic", reportFile); + generator.Initialize(createIssueReportSettings); + generator.CreateReport(issues); + + using (var stream = new FileStream(reportFile, FileMode.Open, FileAccess.Read)) + { + using (var sr = new StreamReader(stream)) + { + return sr.ReadToEnd(); + } + } + } + finally + { + if (File.Exists(reportFile)) + { + File.Delete(reportFile); + } + } + } + + public void TestReportCreation(Action settings) + { + // Given + settings(this.GenericIssueReportFormatSettings); + + // When + var result = + this.CreateReport( + new List + { + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 10) + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Warning) + .Create(), + }); + + // Then + // Currently only checks if generation failed or not without checking actual output. + result.ShouldNotBeNull(); + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFormatSettingsExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFormatSettingsExtensionsTests.cs new file mode 100644 index 000000000..8163a8b83 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFormatSettingsExtensionsTests.cs @@ -0,0 +1,78 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Diagnostics.CodeAnalysis; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class GenericIssueReportFormatSettingsExtensionsTests + { + public sealed class TheWithOptionWithStringKeyMethod + { + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + GenericIssueReportFormatSettings settings = null; + + // When + var result = Record.Exception(() => + settings.WithOption("Foo", "Bar")); + + // Then + result.IsArgumentNullException("settings"); + } + + [Fact] + public void Should_Add_Option() + { + // Given + var key = "Foo"; + var value = "Bar"; + var settings = GenericIssueReportFormatSettings.FromContent("Foo"); + + // When + var result = settings.WithOption(key, value); + + // Then + result.Options.Count.ShouldBe(1); + result.Options.ShouldContainKeyAndValue(key, value); + } + } + + public sealed class TheWithOptionWithEnumKeyMethod + { + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + GenericIssueReportFormatSettings settings = null; + + // When + var result = Record.Exception(() => + settings.WithOption(HtmlDxDataGridOption.Theme, "Bar")); + + // Then + result.IsArgumentNullException("settings"); + } + + [Fact] + public void Should_Add_Option() + { + // Given + var key = HtmlDxDataGridOption.Title; + var value = "Bar"; + var settings = GenericIssueReportFormatSettings.FromContent("Foo"); + + // When + var result = settings.WithOption(key, value); + + // Then + result.Options.Count.ShouldBe(1); + result.Options.ShouldContainKeyAndValue(key.ToString(), value); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFormatSettingsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFormatSettingsTests.cs new file mode 100644 index 000000000..1d16a0a19 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportFormatSettingsTests.cs @@ -0,0 +1,158 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Linq; + using System.Text; + using Cake.Core.IO; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class GenericIssueReportFormatSettingsTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_TemplatePath_Is_Null() + { + // Given + FilePath templatePath = null; + + // When + var result = Record.Exception(() => + GenericIssueReportFormatSettings.FromFilePath(templatePath)); + + // Then + result.IsArgumentNullException("templatePath"); + } + + [Fact] + public void Should_Throw_If_TemplateContent_Is_Null() + { + // Given + string templateContent = null; + + // When + var result = Record.Exception(() => + GenericIssueReportFormatSettings.FromContent(templateContent)); + + // Then + result.IsArgumentNullException("templateContent"); + } + + [Fact] + public void Should_Throw_If_TemplateContent_Is_Empty() + { + // Given + var templateContent = string.Empty; + + // When + var result = Record.Exception(() => + GenericIssueReportFormatSettings.FromContent(templateContent)); + + // Then + result.IsArgumentOutOfRangeException("templateContent"); + } + + [Fact] + public void Should_Throw_If_TemplateContent_Is_WhiteSpace() + { + // Given + var templateContent = " "; + + // When + var result = Record.Exception(() => + GenericIssueReportFormatSettings.FromContent(templateContent)); + + // Then + result.IsArgumentOutOfRangeException("templateContent"); + } + + [Fact] + public void Should_Set_Template() + { + // Given + var templateContent = "foo"; + + // When + var settings = GenericIssueReportFormatSettings.FromContent(templateContent); + + // Then + settings.Template.ShouldBe(templateContent); + } + + [Fact] + public void Should_Set_Embedded_Template() + { + // Given + var template = GenericIssueReportTemplate.HtmlDiagnostic; + + // When + var settings = GenericIssueReportFormatSettings.FromEmbeddedTemplate(template); + + // Then + settings.Template.ShouldNotBeNullOrWhiteSpace(); + } + + [Fact] + public void Should_Read_Template_From_Disk() + { + var fileName = System.IO.Path.GetTempFileName(); + try + { + // Given + string expected; + using (var ms = new MemoryStream()) + using (var stream = this.GetType().Assembly.GetManifestResourceStream("Cake.Issues.Reporting.Generic.Tests.Templates.TestTemplate.cshtml")) + { + if (stream == null) + { + throw new ApplicationException("Resource 'Cake.Issues.Reporting.Generic.Tests.Templates.TestTemplate.cshtml' not found."); + } + + stream.CopyTo(ms); + var data = ms.ToArray(); + + using (var file = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + { + file.Write(data, 0, data.Length); + } + + expected = ConvertFromUtf8(data); + } + + // When + var settings = + GenericIssueReportFormatSettings.FromFilePath(fileName); + + // Then + settings.Template.ShouldBe(expected); + } + finally + { + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + } + } + + private static string ConvertFromUtf8(byte[] bytes) + { + var enc = new UTF8Encoding(true); + var preamble = enc.GetPreamble(); + + if (preamble.Where((p, i) => p != bytes[i]).Any()) + { + throw new ArgumentException("Not utf8-BOM"); + } + + return enc.GetString(bytes.Skip(preamble.Length).ToArray()); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs new file mode 100644 index 000000000..521816793 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportGeneratorTests.cs @@ -0,0 +1,126 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using Cake.Issues.Testing; + using Cake.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class GenericIssueReportGeneratorTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => + new GenericIssueReportGenerator( + null, + GenericIssueReportFormatSettings.FromContent("Foo"))); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given / When + var result = Record.Exception(() => + new GenericIssueReportGenerator( + new FakeLog(), + null)); + + // Then + result.IsArgumentNullException("settings"); + } + } + + public sealed class TheInternalCreateReportMethod + { + [Theory] + [InlineData(GenericIssueReportTemplate.HtmlDiagnostic)] + [InlineData(GenericIssueReportTemplate.HtmlDataTable)] + [InlineData(GenericIssueReportTemplate.HtmlDxDataGrid)] + public void Should_Generate_Report_From_Embedded_Template(GenericIssueReportTemplate template) + { + // Given + var fixture = new GenericIssueReportFixture(template); + var issues = + new List + { + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .WithMessageInHtmlFormat("Message Foo") + .WithMessageInMarkdownFormat("Message **Foo**") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 10) + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Warning) + .Create(), + IssueBuilder + .NewIssue("Message Bar", "ProviderType Bar", "ProviderName Bar") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 12) + .OfRule("Rule Bar") + .WithPriority(IssuePriority.Warning) + .Create(), + }; + + // When + fixture.CreateReport(issues); + + // Then + // No additional tests. We only check if template can be compiled. + } + + [Fact] + public void Should_Generate_Report_From_Custom_Template() + { + // Given + var fixture = new GenericIssueReportFixture("
    @foreach(var issue in Model){
  • @issue.MessageText
  • }
"); + var issues = + new List + { + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 10) + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Warning) + .Create(), + IssueBuilder + .NewIssue("Message Bar", "ProviderType Bar", "ProviderName Bar") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 12) + .OfRule("Rule Bar") + .WithPriority(IssuePriority.Warning) + .Create(), + }; + var expectedResult = + @"
  • Message Foo
  • Message Bar
"; + + // When + var result = fixture.CreateReport(issues); + + // Then + result.ShouldBe(expectedResult); + } + + [Fact] + public void Should_Pass_Options_To_ViewBag() + { + // Given + var expectedResult = "Foo"; + var fixture = new GenericIssueReportFixture("@ViewBag.Title"); + fixture.GenericIssueReportFormatSettings.WithOption("Title", expectedResult); + + // When + var result = fixture.CreateReport(new List()); + + // Then + result.ShouldBe(expectedResult); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportTemplateExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportTemplateExtensionsTests.cs new file mode 100644 index 000000000..e785c174a --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/GenericIssueReportTemplateExtensionsTests.cs @@ -0,0 +1,27 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Diagnostics.CodeAnalysis; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class GenericIssueReportTemplateExtensionsTests + { + public sealed class TheGetTemplateResourceNameMethod + { + [Fact] + public void Should_Return_ResourceName() + { + // Given + var template = GenericIssueReportTemplate.HtmlDiagnostic; + + // When + var result = template.GetTemplateResourceName(); + + // Then + result.ShouldBe("Diagnostic.cshtml"); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxDataGridColumnDescriptionTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxDataGridColumnDescriptionTests.cs new file mode 100644 index 000000000..f6088f494 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxDataGridColumnDescriptionTests.cs @@ -0,0 +1,115 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class HtmlDxDataGridColumnDescriptionTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Id_Is_Null() + { + // Given + string id = null; + static object ValueRetriever(IIssue issue) + { + return true; + } + + // When + var result = Record.Exception(() => new HtmlDxDataGridColumnDescription(id, ValueRetriever)); + + // Then + result.IsArgumentNullException("id"); + } + + [Fact] + public void Should_Throw_If_Id_Is_Empty() + { + // Given + var id = string.Empty; + static object ValueRetriever(IIssue issue) + { + return true; + } + + // When + var result = Record.Exception(() => new HtmlDxDataGridColumnDescription(id, ValueRetriever)); + + // Then + result.IsArgumentOutOfRangeException("id"); + } + + [Fact] + public void Should_Throw_If_Id_Is_Whitespace() + { + // Given + var id = " "; + static object ValueRetriever(IIssue issue) + { + return true; + } + + // When + var result = Record.Exception(() => new HtmlDxDataGridColumnDescription(id, ValueRetriever)); + + // Then + result.IsArgumentOutOfRangeException("id"); + } + + [Fact] + public void Should_Throw_If_ValueRetriever_Is_Null() + { + // Given + var id = "foo"; + Func valueRetriever = null; + + // When + var result = Record.Exception(() => new HtmlDxDataGridColumnDescription(id, valueRetriever)); + + // Then + result.IsArgumentNullException("valueRetriever"); + } + + [Fact] + public void Should_Assign_Id() + { + // Given + var id = "foo"; + static object ValueRetriever(IIssue issue) + { + return true; + } + + // When + var result = new HtmlDxDataGridColumnDescription(id, ValueRetriever); + + // Then + result.Id.ShouldBe(id); + } + + [Fact] + public void Should_Assign_ValueRetriever() + { + // Given + var id = "foo"; + static object ValueRetriever(IIssue issue) + { + return true; + } + + // When + var result = new HtmlDxDataGridColumnDescription(id, ValueRetriever); + + // Then + result.ValueRetriever.ShouldBe(ValueRetriever); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxDataGridTemplateTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxDataGridTemplateTests.cs new file mode 100644 index 000000000..f1c5b7b3d --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/HtmlDxDataGridTemplateTests.cs @@ -0,0 +1,1034 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using HtmlAgilityPack; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class HtmlDxDataGridTemplateTests + { + public sealed class TheTitleOption + { + [Fact] + public void Should_Set_Title() + { + // Given + var title = "Foo"; + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + fixture.GenericIssueReportFormatSettings + .WithOption(HtmlDxDataGridOption.Title, title); + + // When + var result = fixture.CreateReport(new List()); + + // Then + var doc = new HtmlDocument(); + doc.LoadHtml(result); + var titleElements = doc.DocumentNode.Descendants("title").ToList(); + titleElements.ShouldHaveSingleItem(); + titleElements.Single().InnerText.ShouldBe(title); + } + + [Fact] + public void Should_Set_Heading() + { + // Given + var title = "Foo"; + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + fixture.GenericIssueReportFormatSettings + .WithOption(HtmlDxDataGridOption.Title, title); + + // When + var result = fixture.CreateReport(new List()); + + // Then + var doc = new HtmlDocument(); + doc.LoadHtml(result); + var headingElements = doc.DocumentNode.Descendants("h1").ToList(); + headingElements.ShouldHaveSingleItem(); + headingElements.Single().InnerText.ShouldBe(title); + } + } + + public sealed class TheThemeOption + { + public static IEnumerable DevExtremeThemes() + { + return + from object number in Enum.GetValues(typeof(DevExtremeTheme)) + select new[] { number }; + } + + [Theory] + [MemberData(nameof(DevExtremeThemes))] + public void Should_Set_Theme(DevExtremeTheme theme) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + fixture.GenericIssueReportFormatSettings + .WithOption(HtmlDxDataGridOption.Theme, theme); + + // When + var result = fixture.CreateReport(new List()); + + // Then + var doc = new HtmlDocument(); + doc.LoadHtml(result); + var stylesheetElements = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']"); + stylesheetElements.Count.ShouldBe(2); + stylesheetElements.ShouldContain(x => x.Attributes["href"].Value.EndsWith(theme.GetCssFileName())); + } + } + + public sealed class TheShowHeaderOption + { + [Fact] + public void Should_Show_Header_If_True() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + fixture.GenericIssueReportFormatSettings + .WithOption(HtmlDxDataGridOption.ShowHeader, true); + + // When + var result = fixture.CreateReport(new List()); + + // Then + var doc = new HtmlDocument(); + doc.LoadHtml(result); + var headingElements = doc.DocumentNode.Descendants("h1"); + headingElements.ShouldHaveSingleItem(); + } + + [Fact] + public void Should_Not_Show_Header_If_False() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + fixture.GenericIssueReportFormatSettings + .WithOption(HtmlDxDataGridOption.ShowHeader, false); + + // When + var result = fixture.CreateReport(new List()); + + // Then + var doc = new HtmlDocument(); + doc.LoadHtml(result); + var headingElements = doc.DocumentNode.Descendants("h1"); + headingElements.ShouldBeEmpty(); + } + } + + public sealed class TheEnableSearchingOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.EnableSearching, value)); + } + } + + public sealed class TheEnableGroupingOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.EnableGrouping, value)); + } + } + + public sealed class TheEnableFilteringOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.EnableFiltering, value)); + } + } + + public sealed class TheProviderTypeVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProviderTypeVisible, value)); + } + } + + public sealed class TheProviderTypeSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProviderTypeSortOrder, value)); + } + } + + public sealed class TheProviderNameVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProviderNameVisible, value)); + } + } + + public sealed class TheProviderNameSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProviderNameSortOrder, value)); + } + } + + public sealed class TheRunVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RunVisible, value)); + } + } + + public sealed class TheRunSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RunSortOrder, value)); + } + } + + public sealed class ThePriorityVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.PriorityVisible, value)); + } + } + + public sealed class ThePrioritySortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.PrioritySortOrder, value)); + } + } + + public sealed class ThePriorityNameVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.PriorityNameVisible, value)); + } + } + + public sealed class ThePriorityNameSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.PriorityNameSortOrder, value)); + } + } + + public sealed class TheProjectPathVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProjectPathVisible, value)); + } + } + + public sealed class TheProjectPathSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProjectPathSortOrder, value)); + } + } + + public sealed class TheProjectNameVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProjectNameVisible, value)); + } + } + + public sealed class TheProjectNameSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.ProjectNameSortOrder, value)); + } + } + + public sealed class TheFilePathVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.FilePathVisible, value)); + } + } + + public sealed class TheFilePathSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.FilePathSortOrder, value)); + } + } + + public sealed class TheFileDirectoryVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.FileDirectoryVisible, value)); + } + } + + public sealed class TheFileDirectorySortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.FileDirectorySortOrder, value)); + } + } + + public sealed class TheFileNameVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.FileNameVisible, value)); + } + } + + public sealed class TheFileNameSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.FileNameSortOrder, value)); + } + } + + public sealed class TheLineVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.LineVisible, value)); + } + } + + public sealed class TheLineSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.LineSortOrder, value)); + } + } + + public sealed class TheEndLineVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.EndLineVisible, value)); + } + } + + public sealed class TheEndLineSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.EndLineSortOrder, value)); + } + } + + public sealed class TheLocationVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.LocationVisible, value)); + } + } + + public sealed class TheLocationSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.LocationSortOrder, value)); + } + } + + public sealed class TheRuleIdVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RuleIdVisible, value)); + } + } + + public sealed class TheRuleIdSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RuleIdSortOrder, value)); + } + } + + public sealed class TheRuleNameVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RuleNameVisible, value)); + } + } + + public sealed class TheRuleNameSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RuleNameSortOrder, value)); + } + } + + public sealed class TheLRuleUrlVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RuleUrlVisible, value)); + } + } + + public sealed class TheRuleUrlSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.RuleUrlSortOrder, value)); + } + } + + public sealed class TheMessageVisibleOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.MessageVisible, value)); + } + } + + public sealed class TheMessageSortOrderOption + { + [Theory] + [InlineData(ColumnSortOrder.Ascending)] + [InlineData(ColumnSortOrder.Descending)] + public void Should_Not_Fail_On_Report_Creation(ColumnSortOrder value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption(HtmlDxDataGridOption.MessageSortOrder, value)); + } + } + + public sealed class TheGroupedColumnsOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.GroupedColumns, + new List + { + ReportColumn.ProjectName, + ReportColumn.FileDirectory, + ReportColumn.FileName, + })); + } + } + + public sealed class TheSortedColumnsOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.SortedColumns, + new List + { + ReportColumn.RuleId, + ReportColumn.Message, + })); + } + } + + public sealed class TheAdditionalColumnsOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.AdditionalColumns, + new List + { + new("MyCustomColumn", x => "Foo") + { + Caption = "Custom Value", + }, + })); + } + } + + public sealed class TheJQueryLocationOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.JQueryLocation, + "https://foo/")); + } + } + + public sealed class TheJQueryVersionOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.JQueryVersion, + "1.0.0")); + } + } + + public sealed class TheDevExtremeLocationOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.DevExtremeLocation, + "https://foo/")); + } + } + + public sealed class TheDevExtremeVersionOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.DevExtremeVersion, + "19.1.3")); + } + } + + public sealed class TheIdeIntegrationSettingsOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.IdeIntegrationSettings, + new IdeIntegrationSettings())); + } + } + + public sealed class TheEnableExportingOption + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Should_Not_Fail_On_Report_Creation(bool value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.EnableExporting, + value)); + } + } + + public sealed class TheExportFileNameOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.ExportFileName, + "foo")); + } + } + + public sealed class TheExportFormatOption + { + [Theory] + [InlineData(HtmlDxDataGridExportFormat.Excel)] + [InlineData(HtmlDxDataGridExportFormat.Pdf)] + public void Should_Not_Fail_On_Report_Creation(HtmlDxDataGridExportFormat value) + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings + .WithOption( + HtmlDxDataGridOption.EnableExporting, + true) + .WithOption( + HtmlDxDataGridOption.ExportFormat, + value)); + } + } + + public sealed class TheExcelJsLocationOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.ExcelJsLocation, + "foo")); + } + } + + public sealed class TheExcelJsVersionOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.ExcelJsVersion, + "foo")); + } + } + + public sealed class TheFileSaverJsLocationOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.FileSaverJsLocation, + "foo")); + } + } + + public sealed class TheFileSaverJsVersionOption + { + [Fact] + public void Should_Not_Fail_On_Report_Creation() + { + // Given + var fixture = new GenericIssueReportFixture(GenericIssueReportTemplate.HtmlDxDataGrid); + + // When / Then + fixture.TestReportCreation( + settings => + settings.WithOption( + HtmlDxDataGridOption.FileSaverJsVersion, + "foo")); + } + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic.Tests/IIssueExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/IIssueExtensionsTests.cs new file mode 100644 index 000000000..5684b9cee --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/IIssueExtensionsTests.cs @@ -0,0 +1,878 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Follows name of the class which is tested")] + public sealed class IIssueExtensionsTests + { + public sealed class TheGetExpandoObjectExtension + { + [Fact] + public void Should_Throw_If_Issue_Is_Null() + { + // Given + IIssue issue = null; + + // When + var result = Record.Exception(() => issue.GetExpandoObject()); + + // Then + result.IsArgumentNullException("issue"); + } + + [Fact] + public void Should_Set_ProviderType_If_Flag_Is_Set() + { + // Given + var providerType = "ProviderType Foo"; + var issue = + IssueBuilder + .NewIssue("Message Foo", providerType, "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addProviderType: true); + + // Then + ((string)result.ProviderType).ShouldBe(providerType); + } + + [Fact] + public void Should_Not_Set_ProviderType_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addProviderType: false); + var result = Record.Exception(() => expando.ProviderType); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'ProviderType'"); + } + + [Fact] + public void Should_Set_ProviderName_If_Flag_Is_Set() + { + // Given + var providerName = "ProviderName Foo"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", providerName) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addProviderName: true); + + // Then + ((string)result.ProviderName).ShouldBe(providerName); + } + + [Fact] + public void Should_Not_Set_ProviderName_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addProviderName: false); + var result = Record.Exception(() => expando.ProviderName); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'ProviderName'"); + } + + [Fact] + public void Should_Set_Priority_If_Flag_Is_Set() + { + // Given + var priority = IssuePriority.Error; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .WithPriority(priority) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addPriority: true); + + // Then + ((int)result.Priority).ShouldBe((int)priority); + } + + [Fact] + public void Should_Not_Set_Priority_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addPriority: false); + var result = Record.Exception(() => expando.Priority); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'Priority'"); + } + + [Fact] + public void Should_Set_PriorityName_If_Flag_Is_Set() + { + // Given + var priorityName = "Foo"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .WithPriority(0, priorityName) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addPriorityName: true); + + // Then + ((string)result.PriorityName).ShouldBe(priorityName); + } + + [Fact] + public void Should_Not_Set_PriorityName_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addPriorityName: false); + var result = Record.Exception(() => expando.PriorityName); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'PriorityName'"); + } + + [Fact] + public void Should_Set_ProjectPath_If_Flag_Is_Set() + { + // Given + var projectPath = @"src\Cake.Issues.Reporting.Generic.Tests\Cake.Issues.Reporting.Generic.Tests.csproj"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InProjectFile(projectPath) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addProjectPath: true); + + // Then + ((string)result.ProjectPath).ShouldBe(@"src/Cake.Issues.Reporting.Generic.Tests/Cake.Issues.Reporting.Generic.Tests.csproj"); + } + + [Fact] + public void Should_Not_Set_ProjectPath_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addProjectPath: false); + var result = Record.Exception(() => expando.ProjectPath); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'ProjectPath'"); + } + + [Fact] + public void Should_Set_ProjectName_If_Flag_Is_Set() + { + // Given + var projectName = "Cake.Issues.Reporting.Generic.Tests"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InProjectOfName(projectName) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addProjectName: true); + + // Then + ((string)result.ProjectName).ShouldBe(projectName); + } + + [Fact] + public void Should_Not_Set_ProjectName_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addProjectName: false); + var result = Record.Exception(() => expando.ProjectName); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'ProjectName'"); + } + + [Fact] + public void Should_Set_FilePath_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addFilePath: true); + + // Then + ((string)result.FilePath).ShouldBe("src/Cake.Issues.Reporting.Generic.Tests/Foo.cs"); + } + + [Fact] + public void Should_Not_Set_FilePath_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addFilePath: false); + var result = Record.Exception(() => expando.FilePath); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'FilePath'"); + } + + [Fact] + public void Should_Set_FileDirectory_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addFileDirectory: true); + + // Then + ((string)result.FileDirectory).ShouldBe("src/Cake.Issues.Reporting.Generic.Tests"); + } + + [Fact] + public void Should_Not_Set_FileDirectory_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addFileDirectory: false); + var result = Record.Exception(() => expando.FileDirectory); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'FileDirectory'"); + } + + [Fact] + public void Should_Set_FileName_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addFileName: true); + + // Then + ((string)result.FileName).ShouldBe("Foo.cs"); + } + + [Fact] + public void Should_Not_Set_FileName_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addFileName: false); + var result = Record.Exception(() => expando.FileName); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'FileName'"); + } + + [Fact] + public void Should_Set_FileLink_If_Flag_Is_Set() + { + // Given + var fileLink = new Uri("https://github.com"); + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .WithFileLink(fileLink) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addFileLink: true); + + // Then + ((string)result.FileLink).ShouldBe(fileLink.ToString()); + } + + [Fact] + public void Should_Not_Set_FileLink_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addFileLink: false); + var result = Record.Exception(() => expando.FileLink); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'FileLink'"); + } + + [Fact] + public void Should_Set_Line_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var line = 42; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath, 42) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addLine: true); + + // Then + ((int)result.Line).ShouldBe(line); + } + + [Fact] + public void Should_Not_Set_Line_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addLine: false); + var result = Record.Exception(() => expando.Line); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'Line'"); + } + + [Fact] + public void Should_Set_EndLine_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var line = 23; + var endLine = 42; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath, line, endLine, null, null) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addEndLine: true); + + // Then + ((int)result.EndLine).ShouldBe(endLine); + } + + [Fact] + public void Should_Not_Set_EndLine_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addEndLine: false); + var result = Record.Exception(() => expando.EndLine); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'EndLine'"); + } + + [Fact] + public void Should_Set_Column_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var line = 23; + var endLine = 42; + var column = 5; + var endColumn = 10; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath, line, endLine, column, endColumn) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addColumn: true); + + // Then + ((int)result.Column).ShouldBe(column); + } + + [Fact] + public void Should_Not_Set_Column_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addColumn: false); + var result = Record.Exception(() => expando.Column); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'Column'"); + } + + [Fact] + public void Should_Set_EndColumn_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var line = 23; + var endLine = 42; + var column = 5; + var endColumn = 10; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath, line, endLine, column, endColumn) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addEndColumn: true); + + // Then + ((int)result.EndColumn).ShouldBe(endColumn); + } + + [Fact] + public void Should_Not_Set_EndColumn_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addEndColumn: false); + var result = Record.Exception(() => expando.EndColumn); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'EndColumn'"); + } + + [Fact] + public void Should_Set_Location_If_Flag_Is_Set() + { + // Given + var filePath = @"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs"; + var line = 23; + var endLine = 42; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(filePath, line, endLine, null, null) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addLocation: true); + + // Then + ((string)result.Location).ShouldBe($"{line}-{endLine}"); + } + + [Fact] + public void Should_Not_Set_Location_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addLocation: false); + var result = Record.Exception(() => expando.Location); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'Location'"); + } + + [Fact] + public void Should_Set_RuleId_If_Flag_Is_Set() + { + // Given + var ruleId = "foo"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .OfRule(ruleId) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addRuleId: true); + + // Then + ((string)result.RuleId).ShouldBe(ruleId); + } + + [Fact] + public void Should_Not_Set_RuleId_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addRuleId: false); + var result = Record.Exception(() => expando.RuleId); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'RuleId'"); + } + + [Fact] + public void Should_Set_RuleName_If_Flag_Is_Set() + { + // Given + var ruleName = "foo"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .OfRule("ruleId", ruleName) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addRuleName: true); + + // Then + ((string)result.RuleName).ShouldBe(ruleName); + } + + [Fact] + public void Should_Not_Set_RuleName_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addRuleName: false); + var result = Record.Exception(() => expando.RuleName); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'RuleName'"); + } + + [Fact] + public void Should_Set_RuleUrl_If_Flag_Is_Set() + { + // Given + var rule = "foo"; + var ruleUrl = new Uri("https://google.com"); + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .OfRule(rule, ruleUrl) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addRuleUrl: true); + + // Then + ((string)result.RuleUrl).ShouldBe(ruleUrl.ToString()); + } + + [Fact] + public void Should_Not_Set_RuleUrl_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addRuleUrl: false); + var result = Record.Exception(() => expando.RuleUrl); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'RuleUrl'"); + } + + [Fact] + public void Should_Set_MessageText_If_Flag_Is_Set() + { + // Given + var message = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(message, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageText: true); + + // Then + ((string)result.MessageText).ShouldBe(message); + } + + [Fact] + public void Should_Not_Set_MessageText_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addMessageText: false); + var result = Record.Exception(() => expando.MessageText); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'MessageText'"); + } + + [Fact] + public void Should_Set_MessageHtml_If_Flag_Is_Set() + { + // Given + var messageHtml = "Message Foo HTML"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .WithMessageInHtmlFormat(messageHtml) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageHtml: true); + + // Then + ((string)result.MessageHtml).ShouldBe(messageHtml); + } + + [Fact] + public void Should_Not_Set_MessageHtml_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addMessageHtml: false); + var result = Record.Exception(() => expando.MessageHtml); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'MessageHtml'"); + } + + [Fact] + public void Should_Fallback_To_MessageText_If_MessageHtml_Is_Not_Available() + { + // Given + var messageText = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(messageText, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageHtml: true); + + // Then + ((string)result.MessageHtml).ShouldBe(messageText); + } + + [Fact] + public void Should_Fallback_To_MessageText_If_MessageHtml_Is_Not_Available_And_Flag_Is_Set() + { + // Given + var messageText = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(messageText, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageHtml: true, fallbackToTextMessageIfHtmlMessageNotAvailable: true); + + // Then + ((string)result.MessageHtml).ShouldBe(messageText); + } + + [Fact] + public void Should_Not_Fallback_To_MessageText_If_MessageHtml_Is_Not_Available_And_Flag_Is_Not_Set() + { + // Given + var messageText = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(messageText, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageHtml: true, fallbackToTextMessageIfHtmlMessageNotAvailable: false); + + // Then + ((string)result.MessageHtml).ShouldBeNull(); + } + + [Fact] + public void Should_Set_MessageMarkdown_If_Flag_Is_Set() + { + // Given + var messageMarkdown = "Message Foo Markdown"; + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .WithMessageInMarkdownFormat(messageMarkdown) + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageMarkdown: true); + + // Then + ((string)result.MessageMarkdown).ShouldBe(messageMarkdown); + } + + [Fact] + public void Should_Not_Set_MessageMarkdown_If_Flag_Is_Not_Set() + { + // Given + var issue = + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic expando = issue.GetExpandoObject(addMessageMarkdown: false); + var result = Record.Exception(() => expando.MessageMarkdown); + + // Then + result.IsRuntimeBinderException("'System.Dynamic.ExpandoObject' does not contain a definition for 'MessageMarkdown'"); + } + + [Fact] + public void Should_Fallback_To_MessageText_If_MessageMarkdown_Is_Not_Available() + { + // Given + var messageText = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(messageText, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageMarkdown: true); + + // Then + ((string)result.MessageMarkdown).ShouldBe(messageText); + } + + [Fact] + public void Should_Fallback_To_MessageText_If_MessageMarkdown_Is_Not_Available_And_Flag_Is_Set() + { + // Given + var messageText = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(messageText, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageMarkdown: true, fallbackToTextMessageIfMarkdownMessageNotAvailable: true); + + // Then + ((string)result.MessageMarkdown).ShouldBe(messageText); + } + + [Fact] + public void Should_Not_Fallback_To_MessageText_If_MessageMarkdown_Is_Not_Available_And_Flag_Is_Not_Set() + { + // Given + var messageText = "Message Foo"; + var issue = + IssueBuilder + .NewIssue(messageText, "ProviderType Foo", "ProviderName Foo") + .Create(); + + // When + dynamic result = issue.GetExpandoObject(addMessageMarkdown: true, fallbackToTextMessageIfMarkdownMessageNotAvailable: false); + + // Then + ((string)result.MessageMarkdown).ShouldBeNull(); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/IdeIntegrationSettingsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/IdeIntegrationSettingsTests.cs new file mode 100644 index 000000000..a747d9152 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/IdeIntegrationSettingsTests.cs @@ -0,0 +1,539 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Diagnostics.CodeAnalysis; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class IdeIntegrationSettingsTests + { + public sealed class TheGetOpenInIdeCallMethod + { + [Fact] + public void Should_Throw_If_FilePathExpression_Is_Null() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + string filePathExpression = null; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentNullException("filePathExpression"); + } + + [Fact] + public void Should_Throw_If_FilePathExpression_Is_Empty() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = string.Empty; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("filePathExpression"); + } + + [Fact] + public void Should_Throw_If_FilePathExpression_Is_WhiteSpace() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = " "; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("filePathExpression"); + } + + [Fact] + public void Should_Throw_If_LineExpression_Is_Null() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + string lineExpression = null; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentNullException("lineExpression"); + } + + [Fact] + public void Should_Throw_If_LineExpression_Is_Empty() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = string.Empty; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("lineExpression"); + } + + [Fact] + public void Should_Throw_If_LineExpression_Is_WhiteSpace() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = " "; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("lineExpression"); + } + + [Fact] + public void Should_Throw_If_EndLineExpression_Is_Null() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + string endLineExpression = null; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentNullException("endLineExpression"); + } + + [Fact] + public void Should_Throw_If_EndLineExpression_Is_Empty() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = string.Empty; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("endLineExpression"); + } + + [Fact] + public void Should_Throw_If_EndLineExpression_Is_WhiteSpace() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = " "; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("endLineExpression"); + } + + [Fact] + public void Should_Throw_If_ColumnExpression_Is_Null() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + string columnExpression = null; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentNullException("columnExpression"); + } + + [Fact] + public void Should_Throw_If_ColumnExpression_Is_Empty() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = string.Empty; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("columnExpression"); + } + + [Fact] + public void Should_Throw_If_ColumnExpression_Is_WhiteSpace() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = " "; + var endColumnExpression = "endColumn"; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("columnExpression"); + } + + [Fact] + public void Should_Throw_If_EndColumnExpression_Is_Null() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + string endColumnExpression = null; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentNullException("endColumnExpression"); + } + + [Fact] + public void Should_Throw_If_EndColumnExpression_Is_Empty() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = string.Empty; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("endColumnExpression"); + } + + [Fact] + public void Should_Throw_If_EndColumnExpression_Is_WhiteSpace() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = " "; + + // When + var result = Record.Exception(() => + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression)); + + // Then + result.IsArgumentOutOfRangeException("endColumnExpression"); + } + + [Fact] + public void Should_Return_Null_If_OpenInIdeCall_Is_Not_Set() + { + // Given + var ideIntegrationSettings = new IdeIntegrationSettings(); + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression); + + // Then + result.ShouldBeNull(); + } + + [Fact] + public void Should_Replace_FilePath_Token() + { + // Given + var ideIntegrationSettings = + new IdeIntegrationSettings + { + OpenInIdeCall = "Foo{FilePath}Bar", + }; + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression); + + // Then + result.ShouldBe("FoofileBar"); + } + + [Fact] + public void Should_Replace_Line_Token() + { + // Given + var ideIntegrationSettings = + new IdeIntegrationSettings + { + OpenInIdeCall = "Foo{Line}Bar", + }; + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression); + + // Then + result.ShouldBe("FoolineBar"); + } + + [Fact] + public void Should_Replace_EndLine_Token() + { + // Given + var ideIntegrationSettings = + new IdeIntegrationSettings + { + OpenInIdeCall = "Foo{EndLine}Bar", + }; + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression); + + // Then + result.ShouldBe("FooendLineBar"); + } + + [Fact] + public void Should_Replace_Column_Token() + { + // Given + var ideIntegrationSettings = + new IdeIntegrationSettings + { + OpenInIdeCall = "Foo{Column}Bar", + }; + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression); + + // Then + result.ShouldBe("FoocolumnBar"); + } + + [Fact] + public void Should_Replace_EndColumn_Token() + { + // Given + var ideIntegrationSettings = + new IdeIntegrationSettings + { + OpenInIdeCall = "Foo{EndColumn}Bar", + }; + var filePathExpression = "file"; + var lineExpression = "line"; + var endLineExpression = "endLine"; + var columnExpression = "column"; + var endColumnExpression = "endColumn"; + + // When + var result = + ideIntegrationSettings.GetOpenInIdeCall( + filePathExpression, + lineExpression, + endLineExpression, + columnExpression, + endColumnExpression); + + // Then + result.ShouldBe("FooendColumnBar"); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/Properties/ProjectInfo.cs b/src/Cake.Issues.Reporting.Generic.Tests/Properties/ProjectInfo.cs new file mode 100644 index 000000000..88dbe2c88 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/Properties/ProjectInfo.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; +using Xunit; + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1e92a970-e905-4df8-8eca-5529b701e8e3")] + +// There seems to be an issue while executing tests in parallel. See https://github.com/mholo65/gazorator/issues/7 +// This disables test execution when running tests from inside Visual Studio. +// To disable parallelization in build script see xunit.runner.json file. +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/Cake.Issues.Reporting.Generic.Tests/StringExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/StringExtensionsTests.cs new file mode 100644 index 000000000..d227149d4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/StringExtensionsTests.cs @@ -0,0 +1,39 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Diagnostics.CodeAnalysis; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class StringExtensionsTests + { + public sealed class TheSanitizeHtmlIdAttributeExtension + { + [Theory] + [InlineData(null, "")] + [InlineData("", "")] + [InlineData(" ", "")] + [InlineData("foo", "foo")] + [InlineData("foo123", "foo123")] + [InlineData("foo:bar", "foo:bar")] + [InlineData("foo-bar", "foo-bar")] + [InlineData("foo_bar", "foo_bar")] + [InlineData("foo.bar", "foo-bar")] + [InlineData("foo bar", "foo-bar")] + [InlineData("foo@bar", "foo-bar")] + [InlineData("foo🐱bar", "foo-bar")] + [InlineData("123foo", "foo")] + public void Should_Sanitize_Input(string input, string expectedId) + { + // Given + + // When + var result = input.SanitizeHtmlIdAttribute(); + + // Then + result.ShouldBe(expectedId); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/Templates/TestTemplate.cshtml b/src/Cake.Issues.Reporting.Generic.Tests/Templates/TestTemplate.cshtml new file mode 100644 index 000000000..462d2effe --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/Templates/TestTemplate.cshtml @@ -0,0 +1,8 @@ +@model IEnumerable + +
    + @foreach (var issue in Model) + { +
  • @issue.Message
  • + } +
\ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic.Tests/UriExtensionsTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/UriExtensionsTests.cs new file mode 100644 index 000000000..90c86aac4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/UriExtensionsTests.cs @@ -0,0 +1,54 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class UriExtensionsTests + { + public sealed class TheAppendMethod + { + [Fact] + public void Should_Throw_If_Uri_Is_Null() + { + // Given + Uri uri = null; + var path = "foo"; + + // When + var result = Record.Exception(() => + uri.Append(path)); + + // Then + result.IsArgumentNullException("uri"); + } + + [Theory] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com/", "foo", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com", "/foo", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo/", "bar")] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo", "/bar")] + [InlineData("https://google.com/foo/bar/", "https://google.com", "foo", "bar/")] + [InlineData("https://google.com/foo/bar", "https://google.com", "foo/", "/bar")] + [InlineData("https://google.com/bar", "https://google.com", null, "bar")] + [InlineData("https://google.com/bar", "https://google.com", "", "bar")] + [InlineData("https://google.com/bar", "https://google.com", " ", "bar")] + [InlineData("https://google.com/bar", "https://google.com", "/", "/bar")] + public void Should_Append_Paths(string expectedPath, string uri, params string[] paths) + { + // Given + + // When + var result = new Uri(uri).Append(paths); + + // Then + result.ToString().ShouldBe(expectedPath); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/ViewBagHelperTests.cs b/src/Cake.Issues.Reporting.Generic.Tests/ViewBagHelperTests.cs new file mode 100644 index 000000000..1cd7aee33 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/ViewBagHelperTests.cs @@ -0,0 +1,42 @@ +namespace Cake.Issues.Reporting.Generic.Tests +{ + using System.Diagnostics.CodeAnalysis; + using Shouldly; + using Xunit; + + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by test runner")] + [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "By design for null tests")] + public sealed class ViewBagHelperTests + { + public sealed class TheValueOrDefaultMethod + { + [Fact] + public void Should_Return_Value_If_Not_Null() + { + // Given + var value = "foo"; + var defaultValue = "bar"; + + // When + var result = ViewBagHelper.ValueOrDefault(value, defaultValue); + + // Then + result.ShouldBe(value); + } + + [Fact] + public void Should_Return_Default_If_Value_Is_Null() + { + // Given + string value = null; + var defaultValue = "bar"; + + // When + var result = ViewBagHelper.ValueOrDefault(value, defaultValue); + + // Then + result.ShouldBe(defaultValue); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic.Tests/app.config b/src/Cake.Issues.Reporting.Generic.Tests/app.config new file mode 100644 index 000000000..962f2a124 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic.Tests/xunit.runner.json b/src/Cake.Issues.Reporting.Generic.Tests/xunit.runner.json new file mode 100644 index 000000000..80849f37f --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic.Tests/xunit.runner.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "parallelizeTestCollections": false +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj b/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj new file mode 100644 index 000000000..d704df929 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/Cake.Issues.Reporting.Generic.csproj @@ -0,0 +1,48 @@ + + + + net6.0;net7.0;net8.0 + Support for creating issue reports in any text based format (HTML, Markdown, ...) from the Cake.Issues Addin for Cake Build Automation System + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + true + bin\$(Configuration)\$(TargetFramework)\Cake.Issues.Reporting.Generic.xml + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + 1.2.0-beta.556 + + + + + + + + diff --git a/src/Cake.Issues.Reporting.Generic/ColumnSortOrder.cs b/src/Cake.Issues.Reporting.Generic/ColumnSortOrder.cs new file mode 100644 index 000000000..d5c346d9a --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/ColumnSortOrder.cs @@ -0,0 +1,18 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Possible sort orders for columns. + /// + public enum ColumnSortOrder + { + /// + /// Ascending sorting. + /// + Ascending, + + /// + /// Descending sorting. + /// + Descending, + } +} diff --git a/src/Cake.Issues.Reporting.Generic/ColumnSortOrderExtensions.cs b/src/Cake.Issues.Reporting.Generic/ColumnSortOrderExtensions.cs new file mode 100644 index 000000000..0778c098f --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/ColumnSortOrderExtensions.cs @@ -0,0 +1,25 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + + /// + /// Extension methods for the enumeration. + /// + public static class ColumnSortOrderExtensions + { + /// + /// Returns the short identifier of the sort order. + /// + /// Sort order for which the identifier should be returned. + /// Short identifier of the sort order. + public static string ToShortString(this ColumnSortOrder sortOrder) + { + return sortOrder switch + { + ColumnSortOrder.Ascending => "asc", + ColumnSortOrder.Descending => "desc", + _ => throw new ArgumentException("Unknown enumeration value", nameof(sortOrder)), + }; + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/DevExtremeTheme.cs b/src/Cake.Issues.Reporting.Generic/DevExtremeTheme.cs new file mode 100644 index 000000000..86f972ee2 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/DevExtremeTheme.cs @@ -0,0 +1,163 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Available themes for DevExtreme based templates. + /// + public enum DevExtremeTheme + { + /// + /// Light theme. + /// + Light, + + /// + /// Dark theme. + /// + Dark, + + /// + /// High contrast theme. + /// + Contrast, + + /// + /// Carmine theme. + /// + Carmine, + + /// + /// Dark moon theme. + /// + DarkMoon, + + /// + /// Soft blue theme. + /// + SoftBlue, + + /// + /// Dark violet theme. + /// + DarkViolet, + + /// + /// Green mist theme. + /// + GreenMist, + + /// + /// Compact light theme. + /// + LightCompact, + + /// + /// Compact dark theme. + /// + DarkCompact, + + /// + /// Compact and high contrast theme. + /// + ContrastCompact, + + /// + /// Theme in Google Material design in a light blue color scheme. + /// + MaterialBlueLight, + + /// + /// Theme in Google Material design in a light lime color scheme. + /// + MaterialLimeLight, + + /// + /// Theme in Google Material design in a light orange color scheme. + /// + MaterialOrangeLight, + + /// + /// Theme in Google Material design in a light purple color scheme. + /// + MaterialPurpleLight, + + /// + /// Theme in Google Material design in a light teal color scheme. + /// + MaterialTealLight, + + /// + /// Theme in Google Material design in a dark blue color scheme. + /// + MaterialBlueDark, + + /// + /// Theme in Google Material design in a dark lime color scheme. + /// + MaterialLimeDark, + + /// + /// Theme in Google Material design in a dark orange color scheme. + /// + MaterialOrangeDark, + + /// + /// Theme in Google Material design in a dark purple color scheme. + /// + MaterialPurpleDark, + + /// + /// Theme in Google Material design in a dark teal color scheme. + /// + MaterialTealDark, + + /// + /// Theme in Google Material design in a compact light blue color scheme. + /// + MaterialBlueLightCompact, + + /// + /// Theme in Google Material design in a compact light lime color scheme. + /// + MaterialLimeLightCompact, + + /// + /// Theme in Google Material design in a compact light orange color scheme. + /// + MaterialOrangeLightCompact, + + /// + /// Theme in Google Material design in a compact light purple color scheme. + /// + MaterialPurpleLightCompact, + + /// + /// Theme in Google Material design in a compact light teal color scheme. + /// + MaterialTealLightCompact, + + /// + /// Theme in Google Material design in a compact dark blue color scheme. + /// + MaterialBlueDarkCompact, + + /// + /// Theme in Google Material design in a compact dark lime color scheme. + /// + MaterialLimeDarkCompact, + + /// + /// Theme in Google Material design in a compact dark orange color scheme. + /// + MaterialOrangeDarkCompact, + + /// + /// Theme in Google Material design in a compact dark purple color scheme. + /// + MaterialPurpleDarkCompact, + + /// + /// Theme in Google Material design in a compact dark teal color scheme. + /// + MaterialTealDarkCompact, + } +} diff --git a/src/Cake.Issues.Reporting.Generic/DevExtremeThemeExtensions.cs b/src/Cake.Issues.Reporting.Generic/DevExtremeThemeExtensions.cs new file mode 100644 index 000000000..19990edc1 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/DevExtremeThemeExtensions.cs @@ -0,0 +1,54 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + + /// + /// Extension methods for the enumeration. + /// + public static class DevExtremeThemeExtensions + { + /// + /// Returns the CSS file name for a specific DevExtreme theme. + /// + /// Theme for which the CSS file name should be returned. + /// CSS file name of the DevExtreme theme. + public static string GetCssFileName(this DevExtremeTheme theme) + { + return theme switch + { + DevExtremeTheme.Light => "dx.light.css", + DevExtremeTheme.Dark => "dx.dark.css", + DevExtremeTheme.Contrast => "dx.contrast.css", + DevExtremeTheme.Carmine => "dx.carmine.css", + DevExtremeTheme.DarkMoon => "dx.darkmoon.css", + DevExtremeTheme.SoftBlue => "dx.softblue.css", + DevExtremeTheme.DarkViolet => "dx.darkviolet.css", + DevExtremeTheme.GreenMist => "dx.greenmist.css", + DevExtremeTheme.LightCompact => "dx.light.compact.css", + DevExtremeTheme.DarkCompact => "dx.dark.compact.css", + DevExtremeTheme.ContrastCompact => "dx.contrast.compact.css", + DevExtremeTheme.MaterialBlueLight => "dx.material.blue.light.css", + DevExtremeTheme.MaterialLimeLight => "dx.material.lime.light.css", + DevExtremeTheme.MaterialOrangeLight => "dx.material.orange.light.css", + DevExtremeTheme.MaterialPurpleLight => "dx.material.purple.light.css", + DevExtremeTheme.MaterialTealLight => "dx.material.teal.light.css", + DevExtremeTheme.MaterialBlueDark => "dx.material.blue.dark.css", + DevExtremeTheme.MaterialLimeDark => "dx.material.lime.dark.css", + DevExtremeTheme.MaterialOrangeDark => "dx.material.orange.dark.css", + DevExtremeTheme.MaterialPurpleDark => "dx.material.purple.dark.css", + DevExtremeTheme.MaterialTealDark => "dx.material.teal.dark.css", + DevExtremeTheme.MaterialBlueLightCompact => "dx.material.blue.light.compact.css", + DevExtremeTheme.MaterialLimeLightCompact => "dx.material.lime.light.compact.css", + DevExtremeTheme.MaterialOrangeLightCompact => "dx.material.orange.light.compact.css", + DevExtremeTheme.MaterialPurpleLightCompact => "dx.material.purple.light.compact.css", + DevExtremeTheme.MaterialTealLightCompact => "dx.material.teal.light.compact.css", + DevExtremeTheme.MaterialBlueDarkCompact => "dx.material.blue.dark.compact.css", + DevExtremeTheme.MaterialLimeDarkCompact => "dx.material.lime.dark.compact.css", + DevExtremeTheme.MaterialOrangeDarkCompact => "dx.material.orange.dark.compact.css", + DevExtremeTheme.MaterialPurpleDarkCompact => "dx.material.purple.dark.compact.css", + DevExtremeTheme.MaterialTealDarkCompact => "dx.material.teal.dark.compact.css", + _ => throw new ArgumentException("Unknown enumeration value", nameof(theme)), + }; + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/ExpandoObjectExtensions.cs b/src/Cake.Issues.Reporting.Generic/ExpandoObjectExtensions.cs new file mode 100644 index 000000000..d2db271fd --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/ExpandoObjectExtensions.cs @@ -0,0 +1,47 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System.Collections.Generic; + using System.Dynamic; + using System.Linq; + using LitJson; + + /// + /// Extension for . + /// + public static class ExpandoObjectExtensions + { + /// + /// Serializes an to a JSON string. + /// + /// Object which should be serialized. + /// Serialized object. + public static string SerializeToJsonString(this ExpandoObject expandoObject) + { + expandoObject.NotNull(nameof(expandoObject)); + + return + JsonMapper + .ToJson(new Dictionary(expandoObject)); + } + + /// + /// Serializes an to a JSON string. + /// + /// Objects which should be serialized. + /// Serialized objects. + public static string SerializeToJsonString(this IEnumerable expandoObjects) + { + // ReSharper disable PossibleMultipleEnumeration + expandoObjects.NotNull(nameof(expandoObjects)); + + return + JsonMapper + .ToJson( + expandoObjects + .Select(x => new Dictionary(x)) + .ToArray()); + + // ReSharper restore PossibleMultipleEnumeration + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatAliases.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatAliases.cs new file mode 100644 index 000000000..0c503a9b1 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatAliases.cs @@ -0,0 +1,258 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + using System.Diagnostics.CodeAnalysis; + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Core.IO; + + /// + /// Contains functionality for creating issue reports in any text based format (HTML, Markdown, ...). + /// + /// NOTE: Use Cake.Issues.Reporting.Generic addin to use these aliases with Cake Script Runners and + /// Cake.Frosting.Issues.Reporting.Generic to use these aliases with Cake Frosting. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + [SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "Aliases are not used in addin code")] + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global", Justification = "Aliases are called by Cake scripts")] + [SuppressMessage("ReSharper", "UnusedType.Global", Justification = "Class will be loaded by Cake")] + public static class GenericIssueReportFormatAliases + { + /// + /// Gets an instance of a the generic report format using an embedded template. + /// + /// The context. + /// Template to use for generating the report. + /// Instance of a the generic report format. + /// + /// Create HTML report using the diagnostic template: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormatFromEmbeddedTemplate( + this ICakeContext context, + GenericIssueReportTemplate template) + { + context.NotNull(nameof(context)); + + return context.GenericIssueReportFormat(GenericIssueReportFormatSettings.FromEmbeddedTemplate(template)); + } + + /// + /// Gets an instance of a the generic report format using an embedded template with custom settings. + /// + /// The context. + /// Template to use for generating the report. + /// Action for defining the settings. + /// Instance of a the generic report format. + /// + /// Create HTML report using the HtmlDxDataGrid template with custom title: + /// + /// x.WithOption(HtmlDxDataGridOption.Title, "My Issue Report")), + /// @"c:\repo", + /// @"c:\report.html"); + /// ]]> + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormatFromEmbeddedTemplate( + this ICakeContext context, + GenericIssueReportTemplate template, + Action configurator) + { + context.NotNull(nameof(context)); + configurator.NotNull(nameof(configurator)); + + var settings = GenericIssueReportFormatSettings.FromEmbeddedTemplate(template); + configurator(settings); + return context.GenericIssueReportFormat(settings); + } + + /// + /// Gets an instance of a the generic report format using a local template. + /// + /// The context. + /// Path to the template to use for generating the report. + /// Instance of a the generic report format. + /// + /// Create HTML report from local template file: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormatFromFilePath( + this ICakeContext context, + FilePath templatePath) + { + context.NotNull(nameof(context)); + templatePath.NotNull(nameof(templatePath)); + + return context.GenericIssueReportFormat(GenericIssueReportFormatSettings.FromFilePath(templatePath)); + } + + /// + /// Gets an instance of a the generic report format using a local template with custom settings. + /// + /// The context. + /// Path to the template to use for generating the report. + /// Action for defining the settings. + /// Instance of a the generic report format. + /// + /// Create HTML report from local template file with custom title: + /// + /// x.WithOption("Title", "My Issue Report")), + /// @"c:\repo", + /// @"c:\report.html"); + /// ]]> + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormatFromFilePath( + this ICakeContext context, + FilePath templatePath, + Action configurator) + { + context.NotNull(nameof(context)); + templatePath.NotNull(nameof(templatePath)); + configurator.NotNull(nameof(configurator)); + + var settings = GenericIssueReportFormatSettings.FromFilePath(templatePath); + configurator(settings); + return context.GenericIssueReportFormat(settings); + } + + /// + /// Gets an instance of a the generic report format using a template string. + /// + /// The context. + /// Content of the template to use for generating the report. + /// Instance of a the generic report format. + /// + /// Create HTML report from a template string: + /// + /// @foreach(var issue in Model){
  • @issue.Message
  • }"; + /// CreateIssueReport( + /// issues, + /// GenericIssueReportFormatFromContent(template), + /// @"c:\repo", + /// @"c:\report.html"); + /// ]]> + ///
    + ///
    + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormatFromContent( + this ICakeContext context, + string templateContent) + { + context.NotNull(nameof(context)); + templateContent.NotNullOrWhiteSpace(nameof(templateContent)); + + return context.GenericIssueReportFormat(GenericIssueReportFormatSettings.FromContent(templateContent)); + } + + /// + /// Gets an instance of a the generic report format using a template string with custom settings. + /// + /// The context. + /// Content of the template to use for generating the report. + /// Action for defining the settings. + /// Instance of a the generic report format. + /// + /// Create HTML report from a template string with custom title: + /// + /// @ViewBag.Title
      @foreach(var issue in Model){
    • @issue.Message
    • }
    "; + /// CreateIssueReport( + /// issues, + /// GenericIssueReportFormatFromContent( + /// template, + /// x => x.WithOption("Title", "My Issue Report")), + /// @"c:\repo", + /// @"c:\report.html"); + /// ]]> + ///
    + ///
    + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormatFromContent( + this ICakeContext context, + string templateContent, + Action configurator) + { + context.NotNull(nameof(context)); + templateContent.NotNullOrWhiteSpace(nameof(templateContent)); + configurator.NotNull(nameof(configurator)); + + var settings = GenericIssueReportFormatSettings.FromContent(templateContent); + configurator(settings); + return context.GenericIssueReportFormat(settings); + } + + /// + /// Gets an instance of a the generic report format using specified settings. + /// + /// The context. + /// Settings for reading the MSBuild log. + /// Instance of a the generic report format. + /// + /// Create HTML report: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat GenericIssueReportFormat( + this ICakeContext context, + GenericIssueReportFormatSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new GenericIssueReportGenerator(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatSettings.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatSettings.cs new file mode 100644 index 000000000..1433ed038 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatSettings.cs @@ -0,0 +1,103 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + using System.Collections.Generic; + using System.IO; + using Cake.Core.IO; + + /// + /// Settings for . + /// + public class GenericIssueReportFormatSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Template to use for generating the report. + protected GenericIssueReportFormatSettings(GenericIssueReportTemplate template) + { + using (var stream = this.GetType().Assembly.GetManifestResourceStream("Cake.Issues.Reporting.Generic.Templates." + template.GetTemplateResourceName())) + { + if (stream == null) + { + throw new ApplicationException($"Could not load resource {template}"); + } + + using (var sr = new StreamReader(stream)) + { + this.Template = sr.ReadToEnd(); + } + } + } + + /// + /// Initializes a new instance of the class. + /// + /// Path to the template to use for generating the report. + protected GenericIssueReportFormatSettings(FilePath templatePath) + { + templatePath.NotNull(nameof(templatePath)); + + using (var stream = new FileStream(templatePath.FullPath, FileMode.Open, FileAccess.Read)) + { + using (var sr = new StreamReader(stream)) + { + this.Template = sr.ReadToEnd(); + } + } + } + + /// + /// Initializes a new instance of the class. + /// + /// Content of the template to use for generating the report. + protected GenericIssueReportFormatSettings(string templateContent) + { + templateContent.NotNullOrWhiteSpace(nameof(templateContent)); + + this.Template = templateContent; + } + + /// + /// Gets the template to use for generating the report. + /// + public string Template { get; } + + /// + /// Gets the options to use for generating the report. + /// See template for available options. + /// + public Dictionary Options { get; } = []; + + /// + /// Returns a new instance of the class from a template file on disk. + /// + /// Template to use for generating the report. + /// Instance of the class. + public static GenericIssueReportFormatSettings FromEmbeddedTemplate(GenericIssueReportTemplate template) + { + return new GenericIssueReportFormatSettings(template); + } + + /// + /// Returns a new instance of the class from a template file on disk. + /// + /// Path to the template to use for generating the report. + /// Instance of the class. + public static GenericIssueReportFormatSettings FromFilePath(FilePath templatePath) + { + return new GenericIssueReportFormatSettings(templatePath); + } + + /// + /// Returns a new instance of the class from the content + /// of a template file. + /// + /// Content of the template to use for generating the report. + /// Instance of the class. + public static GenericIssueReportFormatSettings FromContent(string templateContent) + { + return new GenericIssueReportFormatSettings(templateContent); + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatSettingsExtensions.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatSettingsExtensions.cs new file mode 100644 index 000000000..7fbf88eb8 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportFormatSettingsExtensions.cs @@ -0,0 +1,42 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + + /// + /// Extension methods for . + /// + public static class GenericIssueReportFormatSettingsExtensions + { + /// + /// Adds an option which should be passed to the template. + /// + /// The settings. + /// Key of the option. + /// Value of the option. + /// The instance with option added to . + public static GenericIssueReportFormatSettings WithOption(this GenericIssueReportFormatSettings settings, string key, object value) + { + settings.NotNull(nameof(settings)); + + settings.Options.Add(key, value); + + return settings; + } + + /// + /// Adds an option which should be passed to the template. + /// + /// The settings. + /// Option which should be set. + /// Value of the option. + /// The instance with option added to . + public static GenericIssueReportFormatSettings WithOption(this GenericIssueReportFormatSettings settings, Enum key, object value) + { + settings.NotNull(nameof(settings)); + + settings.Options.Add(key.ToString(), value); + + return settings; + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportGenerator.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportGenerator.cs new file mode 100644 index 000000000..e9266e54d --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportGenerator.cs @@ -0,0 +1,65 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + using System.Collections.Generic; + using System.IO; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Gazorator; + + /// + /// Generator for creating text based issue reports. + /// + internal class GenericIssueReportGenerator : IssueReportFormat + { + private readonly GenericIssueReportFormatSettings genericIssueReportFormatSettings; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake log context. + /// Settings for reading the log file. + public GenericIssueReportGenerator(ICakeLog log, GenericIssueReportFormatSettings settings) + : base(log) + { + settings.NotNull(nameof(settings)); + + this.genericIssueReportFormatSettings = settings; + } + + /// + protected override FilePath InternalCreateReport(IEnumerable issues) + { + this.Log.Information("Creating report '{0}'", this.Settings.OutputFilePath.FullPath); + + try + { + using (var streamWriter = new StreamWriter(this.Settings.OutputFilePath.FullPath)) + { + Gazorator.Default + .WithOutput(streamWriter) + .WithModel(issues) + .WithReferences( + typeof(System.Linq.Enumerable).Assembly, + typeof(Cake.Issues.IIssue).Assembly, + typeof(Cake.Issues.Reporting.IIssueReportFormat).Assembly, + typeof(Cake.Issues.Reporting.Generic.DevExtremeTheme).Assembly, + typeof(Cake.Core.IO.FilePath).Assembly) + .WithViewBag(this.genericIssueReportFormatSettings.Options) + .ProcessTemplateAsync(this.genericIssueReportFormatSettings.Template) + .ConfigureAwait(false) + .GetAwaiter() + .GetResult(); + } + + return this.Settings.OutputFilePath; + } + catch (Exception e) + { + this.Log.Error(e.Message); + + throw; + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs new file mode 100644 index 000000000..fb1a5ec34 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplate.cs @@ -0,0 +1,24 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Default templates provided by this addin. + /// + public enum GenericIssueReportTemplate + { + /// + /// Template for a HTML report containing a list of all issues with all properties. + /// + HtmlDiagnostic, + + /// + /// Template for a HTML report containing a rich data table view with sorting and search functionality. + /// + HtmlDataTable, + + /// + /// Template for a HTML report containing a rich data grid with sorting, filtering, grouping and search capabilities. + /// See for template specific options. + /// + HtmlDxDataGrid, + } +} diff --git a/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs new file mode 100644 index 000000000..288c4f141 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/GenericIssueReportTemplateExtensions.cs @@ -0,0 +1,26 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + + /// + /// Extension methods for enumeration. + /// + internal static class GenericIssueReportTemplateExtensions + { + /// + /// Returns the name of the embedded template file. + /// + /// Template for which the embedded file name should be returned. + /// Name of the template file. + public static string GetTemplateResourceName(this GenericIssueReportTemplate template) + { + return template switch + { + GenericIssueReportTemplate.HtmlDiagnostic => "Diagnostic.cshtml", + GenericIssueReportTemplate.HtmlDataTable => "DataTable.cshtml", + GenericIssueReportTemplate.HtmlDxDataGrid => "DxDataGrid.cshtml", + _ => throw new ArgumentOutOfRangeException(nameof(template)), + }; + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridColumnDescription.cs b/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridColumnDescription.cs new file mode 100644 index 000000000..0e9ada2a2 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridColumnDescription.cs @@ -0,0 +1,66 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + + /// + /// Description of a column in the template. + /// + public class HtmlDxDataGridColumnDescription + { + /// + /// Initializes a new instance of the class. + /// + /// Id of the column. + /// Function for retrieving the value of the column. + public HtmlDxDataGridColumnDescription(string id, Func valueRetriever) + { + id.NotNullOrWhiteSpace(nameof(id)); + valueRetriever.NotNull(nameof(valueRetriever)); + + this.Id = id; + this.ValueRetriever = valueRetriever; + } + + /// + /// Gets the ID of the column. + /// + public string Id { get; } + + /// + /// Gets a function for retrieving the value of the column. + /// + public Func ValueRetriever { get; } + + /// + /// Gets or sets the caption of the column. + /// + public string Caption { get; set; } + + /// + /// Gets or sets the position of the column regarding other columns. + /// See for values of default columns. + /// Default value is zero, which means that the column will be added before any default columns. + /// + public int VisibleIndex { get; set; } + + /// + /// Gets or sets a value indicating whether data can be filtered by this column or not. + /// Applies only if is set. + /// Default value is true. + /// + public bool AllowFiltering { get; set; } = true; + + /// + /// Gets or sets a value indicating whether the user can group data by values of this column or not. + /// Applies only if is set. + /// Default value is true. + /// + public bool AllowGrouping { get; set; } = true; + + /// + /// Gets or sets a value indicating whether a user can sort rows by this column at runtime or not. + /// Default value is true. + /// + public bool AllowSorting { get; set; } = true; + } +} diff --git a/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridExportFormat.cs b/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridExportFormat.cs new file mode 100644 index 000000000..b5356f398 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridExportFormat.cs @@ -0,0 +1,18 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Available export formats for template. + /// + public enum HtmlDxDataGridExportFormat + { + /// + /// Microsoft Excel (*.xlsx). + /// + Excel, + + /// + /// Portable Document Format (*.pdf). + /// + Pdf, + } +} diff --git a/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption.cs b/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption.cs new file mode 100644 index 000000000..290235c00 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/HtmlDxDataGridOption.cs @@ -0,0 +1,489 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Options for the template. + /// + public enum HtmlDxDataGridOption + { + /// + /// Title of the report. + /// Default value is Issues Report. + /// + Title, + + /// + /// DevExtreme theme to use. + /// See for possible values. + /// Default value is . + /// + Theme, + + /// + /// Flag if the title should be shown as header on the top of the page. + /// Either true or false. + /// Default value is true. + /// + ShowHeader, + + /// + /// Flag if the search panel for full text searching should be visible or not. + /// Either true or false. + /// Default value is true. + /// + EnableSearching, + + /// + /// Flag if the group panel which allows end-user grouping should be visible or not. + /// Either true or false. + /// If false grouping defined by is still applied. + /// Default value is true. + /// + EnableGrouping, + + /// + /// Flag if filtering should be available or not. + /// Either true or false. + /// Default value is true. + /// + EnableFiltering, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + ProviderTypeVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + ProviderTypeSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + ProviderNameVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + ProviderNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true if any issue contains run information, otherwise false. + /// + RunVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + RunSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + PriorityVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + PrioritySortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + PriorityNameVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + PriorityNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + ProjectPathVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + ProjectPathSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + ProjectNameVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + ProjectNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + FilePathVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + FilePathSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + FileDirectoryVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + FileDirectorySortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + FileNameVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + FileNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + LineVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + LineSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + EndLineVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + EndLineSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + ColumnVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + ColumnSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + EndColumnVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + EndColumnSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + LocationVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + LocationSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + RuleIdVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + RuleIdSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + RuleNameVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + RuleNameSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is false. + /// + RuleUrlVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + RuleUrlSortOrder, + + /// + /// Flag if the column should be visible or not. + /// Either true or false. + /// Default value is true. + /// + MessageVisible, + + /// + /// Sort order of the column if it is part of . + /// See for possible values. + /// Default value is . + /// + MessageSortOrder, + + /// + /// List of which should be grouped. + /// Grouped columns are always visible. + /// Default value is and . + /// + GroupedColumns, + + /// + /// List of which should be sorted. + /// Default value is , , + /// , , . + /// + SortedColumns, + + /// + /// List of for additional columns which should be added to the grid. + /// Default value is an empty list. + /// + AdditionalColumns, + + /// + /// Location where jQuery can be found. + /// The following files need to be available: + /// + /// + /// {JQueryLocation}/jquery-{JQueryVersion}.min.js + /// + /// + /// Default value is https://ajax.aspnetcdn.com/ajax/jquery/. + /// + JQueryLocation, + + /// + /// Version of jQuery which should be used. + /// This version needs to match the version required by the selected . + /// Default value is 3.7.0. + /// + JQueryVersion, + + /// + /// Location where the DevExtreme libraries can be found. + /// Below the location there needs to be a folder matching and + /// inside there subfolders js and css. + /// The following files need to be available: + /// + /// + /// {DevExtremeLocation}/{DevExtremeVersion}/js/dx.all.js + /// + /// + /// {DevExtremeLocation}/{DevExtremeVersion}/css/dx.common.css + /// + /// + /// {DevExtremeLocation}/{DevExtremeVersion}/css/{Theme} + /// + /// + /// Default value is https://cdn3.devexpress.com/jslib/. + /// + DevExtremeLocation, + + /// + /// Version of the DevExtreme libraries which should be used. + /// If setting this the matching needs to also be set. + /// Default value is 23.1.6. + /// + DevExtremeVersion, + + /// + /// Settings for having functionality to open files affected by issues in IDEs. + /// Value needs to be an instance of . + /// Default value is null. + /// + IdeIntegrationSettings, + + /// + /// Flag if exporting should be available or not. + /// Either true or false. + /// Default value is false. + /// + EnableExporting, + + /// + /// Default name of the export file without file name extension. + /// Default value is issue-report. + /// + ExportFileName, + + /// + /// Export format. + /// See for possible values. + /// Default value is . + /// + ExportFormat, + + /// + /// Location where ExcelJS can be found. + /// Below the location there needs to be a folder matching . + /// The following files need to be available: + /// + /// + /// {ExcelJsLocation}/{ExcelJsVersion}/exceljs.min.js + /// + /// + /// Default value is https://cdnjs.cloudflare.com/ajax/libs/exceljs/. + /// + ExcelJsLocation, + + /// + /// Version of ExcelJS which should be used. + /// This version needs to match the version required by the selected . + /// Default value is 4.4.0. + /// + ExcelJsVersion, + + /// + /// Location where FileSaver.js can be found. + /// Below the location there needs to be a folder matching . + /// The following files need to be available: + /// + /// + /// {FileSaverLocation}/{FileSaverVersion}/FileSaver.js + /// + /// + /// Default value is https://cdnjs.cloudflare.com/ajax/libs/. + /// + FileSaverJsLocation, + + /// + /// Version of FileSaver.js which should be used. + /// This version needs to match the version required by the selected . + /// Default value is 2.0.5. + /// + FileSaverJsVersion, + + /// + /// Location where jsPDF can be found. + /// Below the location there needs to be a folder matching . + /// The following files need to be available: + /// + /// + /// {JsPdfLocation}/{JsPdfVersion}/jspdf.umd.min.js + /// + /// + /// Default value is https://cdnjs.cloudflare.com/ajax/libs/jspdf/. + /// + JsPdfLocation, + + /// + /// Version of jsPDF which should be used. + /// This version needs to match the version required by the selected . + /// Default value is 2.5.1. + /// + JsPdfVersion, + + /// + /// Location where jsPDF-AutoTable plugin can be found. + /// Below the location there needs to be a folder matching . + /// The following files need to be available: + /// + /// + /// {JsPdfAutotableLocation}/{JsPdfAutotableVersion}/jspdf.plugin.autotable.min.js + /// + /// + /// Default value is https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/. + /// + JsPdfAutotableLocation, + + /// + /// Version of jsPDF-AutoTable plugin which should be used. + /// This version needs to match the version required by the selected . + /// Default value is 3.8.2. + /// + JsPdfAutotableVersion, + } +} diff --git a/src/Cake.Issues.Reporting.Generic/IIssueExtensions.cs b/src/Cake.Issues.Reporting.Generic/IIssueExtensions.cs new file mode 100644 index 000000000..a54cde9ba --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/IIssueExtensions.cs @@ -0,0 +1,203 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + + using System.Dynamic; + + /// + /// Extension for . + /// + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Follows name of the interface which is extended")] + public static class IIssueExtensions + { + /// + /// Returns an dynamic object containing the properties of an issue. + /// + /// Issue for which the dynamic object should be returned. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be added. + /// Flag if value of should be + /// returned if is not available. + /// Flag if value of should be added. + /// Flag if value of should be + /// returned if is not available. + /// Additional values which should be added to the object. + /// Dynamic object containing the properties of the issue. + public static ExpandoObject GetExpandoObject( + this IIssue issue, + bool addProviderType = true, + bool addProviderName = true, + bool addRun = true, + bool addPriority = true, + bool addPriorityName = true, + bool addProjectPath = true, + bool addProjectName = true, + bool addFilePath = true, + bool addFileDirectory = true, + bool addFileName = true, + bool addFileLink = true, + bool addLine = true, + bool addEndLine = true, + bool addColumn = true, + bool addEndColumn = true, + bool addLocation = true, + bool addRuleId = true, + bool addRuleName = true, + bool addRuleUrl = true, + bool addMessageText = true, + bool addMessageHtml = false, + bool fallbackToTextMessageIfHtmlMessageNotAvailable = true, + bool addMessageMarkdown = false, + bool fallbackToTextMessageIfMarkdownMessageNotAvailable = true, + IDictionary> additionalValues = null) + { + issue.NotNull(nameof(issue)); + + dynamic result = new ExpandoObject(); + + if (addProviderType) + { + result.ProviderType = issue.ProviderType; + } + + if (addProviderName) + { + result.ProviderName = issue.ProviderName; + } + + if (addRun) + { + result.Run = issue.Run; + } + + if (addPriority) + { + result.Priority = issue.Priority; + } + + if (addPriorityName) + { + result.PriorityName = issue.PriorityName; + } + + if (addProjectPath) + { + result.ProjectPath = issue.ProjectPath(); + } + + if (addProjectName) + { + result.ProjectName = issue.ProjectName; + } + + if (addFilePath) + { + result.FilePath = issue.FilePath(); + } + + if (addFileDirectory) + { + result.FileDirectory = issue.FileDirectory(); + } + + if (addFileName) + { + result.FileName = issue.FileName(); + } + + if (addFileLink) + { + result.FileLink = issue.FileLink?.ToString(); + } + + if (addLine) + { + result.Line = issue.Line; + } + + if (addEndLine) + { + result.EndLine = issue.EndLine; + } + + if (addColumn) + { + result.Column = issue.Column; + } + + if (addEndColumn) + { + result.EndColumn = issue.EndColumn; + } + + if (addLocation) + { + result.Location = issue.LineRange(); + } + + if (addRuleId) + { + result.RuleId = issue.RuleId; + } + + if (addRuleName) + { + result.RuleName = issue.RuleName; + } + + if (addRuleUrl) + { + result.RuleUrl = issue.RuleUrl?.ToString(); + } + + if (addMessageText) + { + result.MessageText = issue.MessageText; + } + + if (addMessageHtml) + { + result.MessageHtml = + fallbackToTextMessageIfHtmlMessageNotAvailable ? issue.Message(IssueCommentFormat.Html) : issue.MessageHtml; + } + + if (addMessageMarkdown) + { + result.MessageMarkdown = + fallbackToTextMessageIfMarkdownMessageNotAvailable ? issue.Message(IssueCommentFormat.Markdown) : issue.MessageMarkdown; + } + + if (additionalValues != null) + { + var resultDictionary = (IDictionary)result; + foreach (var additionalValue in additionalValues) + { + resultDictionary.Add(additionalValue.Key, additionalValue.Value(issue)); + } + } + + return result; + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/IdeIntegrationSettings.cs b/src/Cake.Issues.Reporting.Generic/IdeIntegrationSettings.cs new file mode 100644 index 000000000..3292b9955 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/IdeIntegrationSettings.cs @@ -0,0 +1,64 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Settings how issues should be integrated to IDEs. + /// + public class IdeIntegrationSettings + { + /// + /// Gets or sets additional JavaScript which should be added. + /// + public string JavaScript { get; set; } + + /// + /// Gets or sets JavaScript which should be called to open the file affected by an issue in an IDE. + /// + public string OpenInIdeCall { get; set; } + + /// + /// Gets or sets text which should be shown in the drop down menu for opening the file affected + /// by an issue in an IDE. + /// Default value is Open in IDE. + /// + public string MenuEntryText { get; set; } = "Open in IDE"; + + /// + /// Returns the JavaScript which should be called to open the file affected by an issue in an IDE + /// with all patterns of replaced. + /// + /// Expression which should be used to get the path and name + /// of the file at runtime. + /// Expression which should be used to get the line number at runtime. + /// Expression which should be used to get the end of the line range at runtime. + /// Expression which should be used to get the column number at runtime. + /// Expression which should be used to get the end of the column range at runtime. + /// JavaScript which should be called to open the file affected by an issue in an IDE + /// with all patterns replaced. + public string GetOpenInIdeCall( + string filePathExpression, + string lineExpression, + string endLineExpression, + string columnExpression, + string endColumnExpression) + { + filePathExpression.NotNullOrWhiteSpace(nameof(filePathExpression)); + lineExpression.NotNullOrWhiteSpace(nameof(lineExpression)); + endLineExpression.NotNullOrWhiteSpace(nameof(endLineExpression)); + columnExpression.NotNullOrWhiteSpace(nameof(columnExpression)); + endColumnExpression.NotNullOrWhiteSpace(nameof(endColumnExpression)); + + if (string.IsNullOrWhiteSpace(this.OpenInIdeCall)) + { + return null; + } + + return + this.OpenInIdeCall + .Replace("{FilePath}", filePathExpression) + .Replace("{Line}", lineExpression) + .Replace("{EndLine}", endLineExpression) + .Replace("{Column}", columnExpression) + .Replace("{EndColumn}", endColumnExpression); + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/IJsonWrapper.cs b/src/Cake.Issues.Reporting.Generic/LitJson/IJsonWrapper.cs new file mode 100644 index 000000000..86806be6a --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/IJsonWrapper.cs @@ -0,0 +1,66 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * IJsonWrapper.cs + * Interface that represents a type capable of handling all kinds of JSON + * data. This is mainly used when mapping objects through JsonMapper, and + * it's implemented by JsonData. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System.Collections; +using System.Collections.Specialized; + + +namespace LitJson +{ + internal enum JsonType + { + None, + + Object, + Array, + String, + Int, + Long, + Double, + Boolean + } + + internal interface IJsonWrapper : IList, IOrderedDictionary + { + bool IsArray { get; } + bool IsBoolean { get; } + bool IsDouble { get; } + bool IsInt { get; } + bool IsLong { get; } + bool IsObject { get; } + bool IsString { get; } + + bool GetBoolean(); + double GetDouble(); + int GetInt(); + JsonType GetJsonType(); + long GetLong(); + string GetString(); + + void SetBoolean(bool val); + void SetDouble(double val); + void SetInt(int val); + void SetJsonType(JsonType type); + void SetLong(long val); + void SetString(string val); + + string ToJson(); + void ToJson(JsonWriter writer); + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/JsonData.cs b/src/Cake.Issues.Reporting.Generic/LitJson/JsonData.cs new file mode 100644 index 000000000..14187beb2 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/JsonData.cs @@ -0,0 +1,1148 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * JsonData.cs + * Generic type to hold JSON data (objects, arrays, and so on). This is + * the default type returned by JsonMapper.ToObject(). + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; + + +namespace LitJson +{ + internal class JsonData : IJsonWrapper, IEquatable + { + #region Fields + private IList inst_array; + private bool inst_boolean; + private double inst_double; + private int inst_int; + private long inst_long; + private IDictionary inst_object; + private string inst_string; + private string json; + private JsonType type; + + // Used to implement the IOrderedDictionary interface + private IList> object_list; + #endregion + + + #region Properties + public int Count + { + get { return EnsureCollection().Count; } + } + + public bool IsArray + { + get { return type == JsonType.Array; } + } + + public bool IsBoolean + { + get { return type == JsonType.Boolean; } + } + + public bool IsDouble + { + get { return type == JsonType.Double; } + } + + public bool IsInt + { + get { return type == JsonType.Int; } + } + + public bool IsLong + { + get { return type == JsonType.Long; } + } + + public bool IsObject + { + get { return type == JsonType.Object; } + } + + public bool IsString + { + get { return type == JsonType.String; } + } + + public ICollection Keys + { + get { EnsureDictionary(); return inst_object.Keys; } + } + + /// + /// Determines whether the json contains an element that has the specified key. + /// + /// The key to locate in the json. + /// true if the json contains an element that has the specified key; otherwise, false. + public Boolean ContainsKey(String key) + { + EnsureDictionary(); + return this.inst_object.Keys.Contains(key); + } + #endregion + + + #region ICollection Properties + int ICollection.Count + { + get + { + return Count; + } + } + + bool ICollection.IsSynchronized + { + get + { + return EnsureCollection().IsSynchronized; + } + } + + object ICollection.SyncRoot + { + get + { + return EnsureCollection().SyncRoot; + } + } + #endregion + + + #region IDictionary Properties + bool IDictionary.IsFixedSize + { + get + { + return EnsureDictionary().IsFixedSize; + } + } + + bool IDictionary.IsReadOnly + { + get + { + return EnsureDictionary().IsReadOnly; + } + } + + ICollection IDictionary.Keys + { + get + { + EnsureDictionary(); + IList keys = new List(); + + foreach (KeyValuePair entry in + object_list) + { + keys.Add(entry.Key); + } + + return (ICollection)keys; + } + } + + ICollection IDictionary.Values + { + get + { + EnsureDictionary(); + IList values = new List(); + + foreach (KeyValuePair entry in + object_list) + { + values.Add(entry.Value); + } + + return (ICollection)values; + } + } + #endregion + + + + #region IJsonWrapper Properties + bool IJsonWrapper.IsArray + { + get { return IsArray; } + } + + bool IJsonWrapper.IsBoolean + { + get { return IsBoolean; } + } + + bool IJsonWrapper.IsDouble + { + get { return IsDouble; } + } + + bool IJsonWrapper.IsInt + { + get { return IsInt; } + } + + bool IJsonWrapper.IsLong + { + get { return IsLong; } + } + + bool IJsonWrapper.IsObject + { + get { return IsObject; } + } + + bool IJsonWrapper.IsString + { + get { return IsString; } + } + #endregion + + + #region IList Properties + bool IList.IsFixedSize + { + get + { + return EnsureList().IsFixedSize; + } + } + + bool IList.IsReadOnly + { + get + { + return EnsureList().IsReadOnly; + } + } + #endregion + + + #region IDictionary Indexer + object IDictionary.this[object key] + { + get + { + return EnsureDictionary()[key]; + } + + set + { + if (!(key is String)) + throw new ArgumentException( + "The key has to be a string"); + + JsonData data = ToJsonData(value); + + this[(string)key] = data; + } + } + #endregion + + + #region IOrderedDictionary Indexer + object IOrderedDictionary.this[int idx] + { + get + { + EnsureDictionary(); + return object_list[idx].Value; + } + + set + { + EnsureDictionary(); + JsonData data = ToJsonData(value); + + KeyValuePair old_entry = object_list[idx]; + + inst_object[old_entry.Key] = data; + + KeyValuePair entry = + new KeyValuePair(old_entry.Key, data); + + object_list[idx] = entry; + } + } + #endregion + + + #region IList Indexer + object IList.this[int index] + { + get + { + return EnsureList()[index]; + } + + set + { + EnsureList(); + JsonData data = ToJsonData(value); + + this[index] = data; + } + } + #endregion + + + #region Public Indexers + public JsonData this[string prop_name] + { + get + { + EnsureDictionary(); + return inst_object[prop_name]; + } + + set + { + EnsureDictionary(); + + KeyValuePair entry = + new KeyValuePair(prop_name, value); + + if (inst_object.ContainsKey(prop_name)) + { + for (int i = 0; i < object_list.Count; i++) + { + if (object_list[i].Key == prop_name) + { + object_list[i] = entry; + break; + } + } + } + else + object_list.Add(entry); + + inst_object[prop_name] = value; + + json = null; + } + } + + public JsonData this[int index] + { + get + { + EnsureCollection(); + + if (type == JsonType.Array) + return inst_array[index]; + + return object_list[index].Value; + } + + set + { + EnsureCollection(); + + if (type == JsonType.Array) + inst_array[index] = value; + else + { + KeyValuePair entry = object_list[index]; + KeyValuePair new_entry = + new KeyValuePair(entry.Key, value); + + object_list[index] = new_entry; + inst_object[entry.Key] = value; + } + + json = null; + } + } + #endregion + + + #region Constructors + public JsonData() + { + } + + public JsonData(bool boolean) + { + type = JsonType.Boolean; + inst_boolean = boolean; + } + + public JsonData(double number) + { + type = JsonType.Double; + inst_double = number; + } + + public JsonData(int number) + { + type = JsonType.Int; + inst_int = number; + } + + public JsonData(long number) + { + type = JsonType.Long; + inst_long = number; + } + + public JsonData(object obj) + { + if (obj is Boolean) + { + type = JsonType.Boolean; + inst_boolean = (bool)obj; + return; + } + + if (obj is Double) + { + type = JsonType.Double; + inst_double = (double)obj; + return; + } + + if (obj is Int32) + { + type = JsonType.Int; + inst_int = (int)obj; + return; + } + + if (obj is Int64) + { + type = JsonType.Long; + inst_long = (long)obj; + return; + } + + if (obj is String) + { + type = JsonType.String; + inst_string = (string)obj; + return; + } + + throw new ArgumentException( + "Unable to wrap the given object with JsonData"); + } + + public JsonData(string str) + { + type = JsonType.String; + inst_string = str; + } + #endregion + + + #region Implicit Conversions + public static implicit operator JsonData(Boolean data) + { + return new JsonData(data); + } + + public static implicit operator JsonData(Double data) + { + return new JsonData(data); + } + + public static implicit operator JsonData(Int32 data) + { + return new JsonData(data); + } + + public static implicit operator JsonData(Int64 data) + { + return new JsonData(data); + } + + public static implicit operator JsonData(String data) + { + return new JsonData(data); + } + #endregion + + + #region Explicit Conversions + public static explicit operator Boolean(JsonData data) + { + if (data.type != JsonType.Boolean) + throw new InvalidCastException( + "Instance of JsonData doesn't hold a double"); + + return data.inst_boolean; + } + + public static explicit operator Double(JsonData data) + { + if (data.type != JsonType.Double) + throw new InvalidCastException( + "Instance of JsonData doesn't hold a double"); + + return data.inst_double; + } + + public static explicit operator Int32(JsonData data) + { + if (data.type != JsonType.Int && data.type != JsonType.Long) + { + throw new InvalidCastException( + "Instance of JsonData doesn't hold an int"); + } + + // cast may truncate data... but that's up to the user to consider + return data.type == JsonType.Int ? data.inst_int : (int)data.inst_long; + } + + public static explicit operator Int64(JsonData data) + { + if (data.type != JsonType.Long && data.type != JsonType.Int) + { + throw new InvalidCastException( + "Instance of JsonData doesn't hold a long"); + } + + return data.type == JsonType.Long ? data.inst_long : data.inst_int; + } + + public static explicit operator String(JsonData data) + { + if (data.type != JsonType.String) + throw new InvalidCastException( + "Instance of JsonData doesn't hold a string"); + + return data.inst_string; + } + #endregion + + + #region ICollection Methods + void ICollection.CopyTo(Array array, int index) + { + EnsureCollection().CopyTo(array, index); + } + #endregion + + + #region IDictionary Methods + void IDictionary.Add(object key, object value) + { + JsonData data = ToJsonData(value); + + EnsureDictionary().Add(key, data); + + KeyValuePair entry = + new KeyValuePair((string)key, data); + object_list.Add(entry); + + json = null; + } + + void IDictionary.Clear() + { + EnsureDictionary().Clear(); + object_list.Clear(); + json = null; + } + + bool IDictionary.Contains(object key) + { + return EnsureDictionary().Contains(key); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return ((IOrderedDictionary)this).GetEnumerator(); + } + + void IDictionary.Remove(object key) + { + EnsureDictionary().Remove(key); + + for (int i = 0; i < object_list.Count; i++) + { + if (object_list[i].Key == (string)key) + { + object_list.RemoveAt(i); + break; + } + } + + json = null; + } + #endregion + + + #region IEnumerable Methods + IEnumerator IEnumerable.GetEnumerator() + { + return EnsureCollection().GetEnumerator(); + } + #endregion + + + #region IJsonWrapper Methods + bool IJsonWrapper.GetBoolean() + { + if (type != JsonType.Boolean) + throw new InvalidOperationException( + "JsonData instance doesn't hold a boolean"); + + return inst_boolean; + } + + double IJsonWrapper.GetDouble() + { + if (type != JsonType.Double) + throw new InvalidOperationException( + "JsonData instance doesn't hold a double"); + + return inst_double; + } + + int IJsonWrapper.GetInt() + { + if (type != JsonType.Int) + throw new InvalidOperationException( + "JsonData instance doesn't hold an int"); + + return inst_int; + } + + long IJsonWrapper.GetLong() + { + if (type != JsonType.Long) + throw new InvalidOperationException( + "JsonData instance doesn't hold a long"); + + return inst_long; + } + + string IJsonWrapper.GetString() + { + if (type != JsonType.String) + throw new InvalidOperationException( + "JsonData instance doesn't hold a string"); + + return inst_string; + } + + void IJsonWrapper.SetBoolean(bool val) + { + type = JsonType.Boolean; + inst_boolean = val; + json = null; + } + + void IJsonWrapper.SetDouble(double val) + { + type = JsonType.Double; + inst_double = val; + json = null; + } + + void IJsonWrapper.SetInt(int val) + { + type = JsonType.Int; + inst_int = val; + json = null; + } + + void IJsonWrapper.SetLong(long val) + { + type = JsonType.Long; + inst_long = val; + json = null; + } + + void IJsonWrapper.SetString(string val) + { + type = JsonType.String; + inst_string = val; + json = null; + } + + string IJsonWrapper.ToJson() + { + return ToJson(); + } + + void IJsonWrapper.ToJson(JsonWriter writer) + { + ToJson(writer); + } + #endregion + + + #region IList Methods + int IList.Add(object value) + { + return Add(value); + } + + void IList.Clear() + { + EnsureList().Clear(); + json = null; + } + + bool IList.Contains(object value) + { + return EnsureList().Contains(value); + } + + int IList.IndexOf(object value) + { + return EnsureList().IndexOf(value); + } + + void IList.Insert(int index, object value) + { + EnsureList().Insert(index, value); + json = null; + } + + void IList.Remove(object value) + { + EnsureList().Remove(value); + json = null; + } + + void IList.RemoveAt(int index) + { + EnsureList().RemoveAt(index); + json = null; + } + #endregion + + + #region IOrderedDictionary Methods + IDictionaryEnumerator IOrderedDictionary.GetEnumerator() + { + EnsureDictionary(); + + return new OrderedDictionaryEnumerator( + object_list.GetEnumerator()); + } + + void IOrderedDictionary.Insert(int idx, object key, object value) + { + string property = (string)key; + JsonData data = ToJsonData(value); + + this[property] = data; + + KeyValuePair entry = + new KeyValuePair(property, data); + + object_list.Insert(idx, entry); + } + + void IOrderedDictionary.RemoveAt(int idx) + { + EnsureDictionary(); + + inst_object.Remove(object_list[idx].Key); + object_list.RemoveAt(idx); + } + #endregion + + + #region Private Methods + private ICollection EnsureCollection() + { + if (type == JsonType.Array) + return (ICollection)inst_array; + + if (type == JsonType.Object) + return (ICollection)inst_object; + + throw new InvalidOperationException( + "The JsonData instance has to be initialized first"); + } + + private IDictionary EnsureDictionary() + { + if (type == JsonType.Object) + return (IDictionary)inst_object; + + if (type != JsonType.None) + throw new InvalidOperationException( + "Instance of JsonData is not a dictionary"); + + type = JsonType.Object; + inst_object = new Dictionary(); + object_list = new List>(); + + return (IDictionary)inst_object; + } + + private IList EnsureList() + { + if (type == JsonType.Array) + return (IList)inst_array; + + if (type != JsonType.None) + throw new InvalidOperationException( + "Instance of JsonData is not a list"); + + type = JsonType.Array; + inst_array = new List(); + + return (IList)inst_array; + } + + private JsonData ToJsonData(object obj) + { + if (obj == null) + return null; + + if (obj is JsonData) + return (JsonData)obj; + + return new JsonData(obj); + } + + private static void WriteJson(IJsonWrapper obj, JsonWriter writer) + { + if (obj == null) + { + writer.Write(null); + return; + } + + if (obj.IsString) + { + writer.Write(obj.GetString()); + return; + } + + if (obj.IsBoolean) + { + writer.Write(obj.GetBoolean()); + return; + } + + if (obj.IsDouble) + { + writer.Write(obj.GetDouble()); + return; + } + + if (obj.IsInt) + { + writer.Write(obj.GetInt()); + return; + } + + if (obj.IsLong) + { + writer.Write(obj.GetLong()); + return; + } + + if (obj.IsArray) + { + writer.WriteArrayStart(); + foreach (object elem in (IList)obj) + WriteJson((JsonData)elem, writer); + writer.WriteArrayEnd(); + + return; + } + + if (obj.IsObject) + { + writer.WriteObjectStart(); + + foreach (DictionaryEntry entry in ((IDictionary)obj)) + { + writer.WritePropertyName((string)entry.Key); + WriteJson((JsonData)entry.Value, writer); + } + writer.WriteObjectEnd(); + + return; + } + } + #endregion + + + public int Add(object value) + { + JsonData data = ToJsonData(value); + + json = null; + + return EnsureList().Add(data); + } + + public bool Remove(object obj) + { + json = null; + if (IsObject) + { + JsonData value = null; + if (inst_object.TryGetValue((string)obj, out value)) + return inst_object.Remove((string)obj) && object_list.Remove(new KeyValuePair((string)obj, value)); + else + throw new KeyNotFoundException("The specified key was not found in the JsonData object."); + } + if (IsArray) + { + return inst_array.Remove(ToJsonData(obj)); + } + throw new InvalidOperationException( + "Instance of JsonData is not an object or a list."); + } + + public void Clear() + { + if (IsObject) + { + ((IDictionary)this).Clear(); + return; + } + + if (IsArray) + { + ((IList)this).Clear(); + return; + } + } + + public bool Equals(JsonData x) + { + if (x == null) + return false; + + if (x.type != this.type) + { + // further check to see if this is a long to int comparison + if ((x.type != JsonType.Int && x.type != JsonType.Long) + || (this.type != JsonType.Int && this.type != JsonType.Long)) + { + return false; + } + } + + switch (this.type) + { + case JsonType.None: + return true; + + case JsonType.Object: + return this.inst_object.Equals(x.inst_object); + + case JsonType.Array: + return this.inst_array.Equals(x.inst_array); + + case JsonType.String: + return this.inst_string.Equals(x.inst_string); + + case JsonType.Int: + { + if (x.IsLong) + { + if (x.inst_long < Int32.MinValue || x.inst_long > Int32.MaxValue) + return false; + return this.inst_int.Equals((int)x.inst_long); + } + return this.inst_int.Equals(x.inst_int); + } + + case JsonType.Long: + { + if (x.IsInt) + { + if (this.inst_long < Int32.MinValue || this.inst_long > Int32.MaxValue) + return false; + return x.inst_int.Equals((int)this.inst_long); + } + return this.inst_long.Equals(x.inst_long); + } + + case JsonType.Double: + return this.inst_double.Equals(x.inst_double); + + case JsonType.Boolean: + return this.inst_boolean.Equals(x.inst_boolean); + } + + return false; + } + + public JsonType GetJsonType() + { + return type; + } + + public void SetJsonType(JsonType type) + { + if (this.type == type) + return; + + switch (type) + { + case JsonType.None: + break; + + case JsonType.Object: + inst_object = new Dictionary(); + object_list = new List>(); + break; + + case JsonType.Array: + inst_array = new List(); + break; + + case JsonType.String: + inst_string = default(String); + break; + + case JsonType.Int: + inst_int = default(Int32); + break; + + case JsonType.Long: + inst_long = default(Int64); + break; + + case JsonType.Double: + inst_double = default(Double); + break; + + case JsonType.Boolean: + inst_boolean = default(Boolean); + break; + } + + this.type = type; + } + + public string ToJson() + { + if (json != null) + return json; + + StringWriter sw = new StringWriter(); + JsonWriter writer = new JsonWriter(sw); + writer.Validate = false; + + WriteJson(this, writer); + json = sw.ToString(); + + return json; + } + + public void ToJson(JsonWriter writer) + { + bool old_validate = writer.Validate; + + writer.Validate = false; + + WriteJson(this, writer); + + writer.Validate = old_validate; + } + + public override string ToString() + { + switch (type) + { + case JsonType.Array: + return "JsonData array"; + + case JsonType.Boolean: + return inst_boolean.ToString(); + + case JsonType.Double: + return inst_double.ToString(); + + case JsonType.Int: + return inst_int.ToString(); + + case JsonType.Long: + return inst_long.ToString(); + + case JsonType.Object: + return "JsonData object"; + + case JsonType.String: + return inst_string; + } + + return "Uninitialized JsonData"; + } + } + + + internal class OrderedDictionaryEnumerator : IDictionaryEnumerator + { + IEnumerator> list_enumerator; + + + public object Current + { + get { return Entry; } + } + + public DictionaryEntry Entry + { + get + { + KeyValuePair curr = list_enumerator.Current; + return new DictionaryEntry(curr.Key, curr.Value); + } + } + + public object Key + { + get { return list_enumerator.Current.Key; } + } + + public object Value + { + get { return list_enumerator.Current.Value; } + } + + + public OrderedDictionaryEnumerator( + IEnumerator> enumerator) + { + list_enumerator = enumerator; + } + + + public bool MoveNext() + { + return list_enumerator.MoveNext(); + } + + public void Reset() + { + list_enumerator.Reset(); + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/JsonException.cs b/src/Cake.Issues.Reporting.Generic/LitJson/JsonException.cs new file mode 100644 index 000000000..a9232e4fa --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/JsonException.cs @@ -0,0 +1,71 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * JsonException.cs + * Base class throwed by LitJSON when a parsing error occurs. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; + + +namespace LitJson +{ + internal class JsonException : +#if NETSTANDARD1_5 + Exception +#else + ApplicationException +#endif + { + public JsonException() : base() + { + } + + internal JsonException(ParserToken token) : + base(String.Format( + "Invalid token '{0}' in input string", token)) + { + } + + internal JsonException(ParserToken token, + Exception inner_exception) : + base(String.Format( + "Invalid token '{0}' in input string", token), + inner_exception) + { + } + + internal JsonException(int c) : + base(String.Format( + "Invalid character '{0}' in input string", (char)c)) + { + } + + internal JsonException(int c, Exception inner_exception) : + base(String.Format( + "Invalid character '{0}' in input string", (char)c), + inner_exception) + { + } + + + public JsonException(string message) : base(message) + { + } + + public JsonException(string message, Exception inner_exception) : + base(message, inner_exception) + { + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/JsonMapper.cs b/src/Cake.Issues.Reporting.Generic/LitJson/JsonMapper.cs new file mode 100644 index 000000000..24873ab7a --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/JsonMapper.cs @@ -0,0 +1,1077 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * JsonMapper.cs + * JSON to .Net object and object to JSON conversions. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Reflection; + + +namespace LitJson +{ + internal struct PropertyMetadata + { + public MemberInfo Info; + public bool IsField; + public Type Type; + } + + + internal struct ArrayMetadata + { + private Type element_type; + private bool is_array; + private bool is_list; + + + public Type ElementType + { + get + { + if (element_type == null) + return typeof(JsonData); + + return element_type; + } + + set { element_type = value; } + } + + public bool IsArray + { + get { return is_array; } + set { is_array = value; } + } + + public bool IsList + { + get { return is_list; } + set { is_list = value; } + } + } + + + internal struct ObjectMetadata + { + private Type element_type; + private bool is_dictionary; + + private IDictionary properties; + + + public Type ElementType + { + get + { + if (element_type == null) + return typeof(JsonData); + + return element_type; + } + + set { element_type = value; } + } + + public bool IsDictionary + { + get { return is_dictionary; } + set { is_dictionary = value; } + } + + public IDictionary Properties + { + get { return properties; } + set { properties = value; } + } + } + + + internal delegate void ExporterFunc(object obj, JsonWriter writer); + internal delegate void ExporterFunc(T obj, JsonWriter writer); + + internal delegate object ImporterFunc(object input); + internal delegate TValue ImporterFunc(TJson input); + + internal delegate IJsonWrapper WrapperFactory(); + + + internal class JsonMapper + { + #region Fields + private static readonly int max_nesting_depth; + + private static readonly IFormatProvider datetime_format; + + private static readonly IDictionary base_exporters_table; + private static readonly IDictionary custom_exporters_table; + + private static readonly IDictionary> base_importers_table; + private static readonly IDictionary> custom_importers_table; + + private static readonly IDictionary array_metadata; + private static readonly object array_metadata_lock = new Object(); + + private static readonly IDictionary> conv_ops; + private static readonly object conv_ops_lock = new Object(); + + private static readonly IDictionary object_metadata; + private static readonly object object_metadata_lock = new Object(); + + private static readonly IDictionary> type_properties; + private static readonly object type_properties_lock = new Object(); + + private static readonly JsonWriter static_writer; + private static readonly object static_writer_lock = new Object(); + #endregion + + + #region Constructors + static JsonMapper() + { + max_nesting_depth = 100; + + array_metadata = new Dictionary(); + conv_ops = new Dictionary>(); + object_metadata = new Dictionary(); + type_properties = new Dictionary>(); + + static_writer = new JsonWriter(); + + datetime_format = DateTimeFormatInfo.InvariantInfo; + + base_exporters_table = new Dictionary(); + custom_exporters_table = new Dictionary(); + + base_importers_table = new Dictionary>(); + custom_importers_table = new Dictionary>(); + + RegisterBaseExporters(); + RegisterBaseImporters(); + } + #endregion + + + #region Private Methods + private static void AddArrayMetadata(Type type) + { + if (array_metadata.ContainsKey(type)) + return; + + ArrayMetadata data = new ArrayMetadata(); + + data.IsArray = type.IsArray; + + if (type.GetInterface("System.Collections.IList") != null) + data.IsList = true; + + foreach (PropertyInfo p_info in type.GetProperties()) + { + if (p_info.Name != "Item") + continue; + + ParameterInfo[] parameters = p_info.GetIndexParameters(); + + if (parameters.Length != 1) + continue; + + if (parameters[0].ParameterType == typeof(int)) + data.ElementType = p_info.PropertyType; + } + + lock (array_metadata_lock) + { + try + { + array_metadata.Add(type, data); + } + catch (ArgumentException) + { + return; + } + } + } + + private static void AddObjectMetadata(Type type) + { + if (object_metadata.ContainsKey(type)) + return; + + ObjectMetadata data = new ObjectMetadata(); + + if (type.GetInterface("System.Collections.IDictionary") != null) + data.IsDictionary = true; + + data.Properties = new Dictionary(); + + foreach (PropertyInfo p_info in type.GetProperties()) + { + if (p_info.Name == "Item") + { + ParameterInfo[] parameters = p_info.GetIndexParameters(); + + if (parameters.Length != 1) + continue; + + if (parameters[0].ParameterType == typeof(string)) + data.ElementType = p_info.PropertyType; + + continue; + } + + PropertyMetadata p_data = new PropertyMetadata(); + p_data.Info = p_info; + p_data.Type = p_info.PropertyType; + + data.Properties.Add(p_info.Name, p_data); + } + + foreach (FieldInfo f_info in type.GetFields()) + { + PropertyMetadata p_data = new PropertyMetadata(); + p_data.Info = f_info; + p_data.IsField = true; + p_data.Type = f_info.FieldType; + + data.Properties.Add(f_info.Name, p_data); + } + + lock (object_metadata_lock) + { + try + { + object_metadata.Add(type, data); + } + catch (ArgumentException) + { + return; + } + } + } + + private static void AddTypeProperties(Type type) + { + if (type_properties.ContainsKey(type)) + return; + + IList props = new List(); + + foreach (PropertyInfo p_info in type.GetProperties()) + { + if (p_info.Name == "Item") + continue; + + PropertyMetadata p_data = new PropertyMetadata(); + p_data.Info = p_info; + p_data.IsField = false; + props.Add(p_data); + } + + foreach (FieldInfo f_info in type.GetFields()) + { + PropertyMetadata p_data = new PropertyMetadata(); + p_data.Info = f_info; + p_data.IsField = true; + + props.Add(p_data); + } + + lock (type_properties_lock) + { + try + { + type_properties.Add(type, props); + } + catch (ArgumentException) + { + return; + } + } + } + + private static MethodInfo GetConvOp(Type t1, Type t2) + { + lock (conv_ops_lock) + { + if (!conv_ops.ContainsKey(t1)) + conv_ops.Add(t1, new Dictionary()); + } + + if (conv_ops[t1].ContainsKey(t2)) + return conv_ops[t1][t2]; + + MethodInfo op = t1.GetMethod( + "op_Implicit", new Type[] { t2 }); + + lock (conv_ops_lock) + { + try + { + conv_ops[t1].Add(t2, op); + } + catch (ArgumentException) + { + return conv_ops[t1][t2]; + } + } + + return op; + } + + private static object ReadValue(Type inst_type, JsonReader reader) + { + reader.Read(); + + if (reader.Token == JsonToken.ArrayEnd) + return null; + + Type underlying_type = Nullable.GetUnderlyingType(inst_type); + Type value_type = underlying_type ?? inst_type; + + if (reader.Token == JsonToken.Null) + { +#if NETSTANDARD1_5 + if (inst_type.IsClass() || underlying_type != null) { + return null; + } +#else + if (inst_type.IsClass || underlying_type != null) + { + return null; + } +#endif + + throw new JsonException(String.Format( + "Can't assign null to an instance of type {0}", + inst_type)); + } + + if (reader.Token == JsonToken.Double || + reader.Token == JsonToken.Int || + reader.Token == JsonToken.Long || + reader.Token == JsonToken.String || + reader.Token == JsonToken.Boolean) + { + + Type json_type = reader.Value.GetType(); + + if (value_type.IsAssignableFrom(json_type)) + return reader.Value; + + // If there's a custom importer that fits, use it + if (custom_importers_table.ContainsKey(json_type) && + custom_importers_table[json_type].ContainsKey( + value_type)) + { + + ImporterFunc importer = + custom_importers_table[json_type][value_type]; + + return importer(reader.Value); + } + + // Maybe there's a base importer that works + if (base_importers_table.ContainsKey(json_type) && + base_importers_table[json_type].ContainsKey( + value_type)) + { + + ImporterFunc importer = + base_importers_table[json_type][value_type]; + + return importer(reader.Value); + } + + // Maybe it's an enum +#if NETSTANDARD1_5 + if (value_type.IsEnum()) + return Enum.ToObject (value_type, reader.Value); +#else + if (value_type.IsEnum) + return Enum.ToObject(value_type, reader.Value); +#endif + // Try using an implicit conversion operator + MethodInfo conv_op = GetConvOp(value_type, json_type); + + if (conv_op != null) + return conv_op.Invoke(null, + new object[] { reader.Value }); + + // No luck + throw new JsonException(String.Format( + "Can't assign value '{0}' (type {1}) to type {2}", + reader.Value, json_type, inst_type)); + } + + object instance = null; + + if (reader.Token == JsonToken.ArrayStart) + { + + AddArrayMetadata(inst_type); + ArrayMetadata t_data = array_metadata[inst_type]; + + if (!t_data.IsArray && !t_data.IsList) + throw new JsonException(String.Format( + "Type {0} can't act as an array", + inst_type)); + + IList list; + Type elem_type; + + if (!t_data.IsArray) + { + list = (IList)Activator.CreateInstance(inst_type); + elem_type = t_data.ElementType; + } + else + { + list = new ArrayList(); + elem_type = inst_type.GetElementType(); + } + + list.Clear(); + + while (true) + { + object item = ReadValue(elem_type, reader); + if (item == null && reader.Token == JsonToken.ArrayEnd) + break; + + list.Add(item); + } + + if (t_data.IsArray) + { + int n = list.Count; + instance = Array.CreateInstance(elem_type, n); + + for (int i = 0; i < n; i++) + ((Array)instance).SetValue(list[i], i); + } + else + instance = list; + + } + else if (reader.Token == JsonToken.ObjectStart) + { + AddObjectMetadata(value_type); + ObjectMetadata t_data = object_metadata[value_type]; + + instance = Activator.CreateInstance(value_type); + + while (true) + { + reader.Read(); + + if (reader.Token == JsonToken.ObjectEnd) + break; + + string property = (string)reader.Value; + + if (t_data.Properties.ContainsKey(property)) + { + PropertyMetadata prop_data = + t_data.Properties[property]; + + if (prop_data.IsField) + { + ((FieldInfo)prop_data.Info).SetValue( + instance, ReadValue(prop_data.Type, reader)); + } + else + { + PropertyInfo p_info = + (PropertyInfo)prop_data.Info; + + if (p_info.CanWrite) + p_info.SetValue( + instance, + ReadValue(prop_data.Type, reader), + null); + else + ReadValue(prop_data.Type, reader); + } + + } + else + { + if (!t_data.IsDictionary) + { + + if (!reader.SkipNonMembers) + { + throw new JsonException(String.Format( + "The type {0} doesn't have the " + + "property '{1}'", + inst_type, property)); + } + else + { + ReadSkip(reader); + continue; + } + } + + ((IDictionary)instance).Add( + property, ReadValue( + t_data.ElementType, reader)); + } + + } + + } + + return instance; + } + + private static IJsonWrapper ReadValue(WrapperFactory factory, + JsonReader reader) + { + reader.Read(); + + if (reader.Token == JsonToken.ArrayEnd || + reader.Token == JsonToken.Null) + return null; + + IJsonWrapper instance = factory(); + + if (reader.Token == JsonToken.String) + { + instance.SetString((string)reader.Value); + return instance; + } + + if (reader.Token == JsonToken.Double) + { + instance.SetDouble((double)reader.Value); + return instance; + } + + if (reader.Token == JsonToken.Int) + { + instance.SetInt((int)reader.Value); + return instance; + } + + if (reader.Token == JsonToken.Long) + { + instance.SetLong((long)reader.Value); + return instance; + } + + if (reader.Token == JsonToken.Boolean) + { + instance.SetBoolean((bool)reader.Value); + return instance; + } + + if (reader.Token == JsonToken.ArrayStart) + { + instance.SetJsonType(JsonType.Array); + + while (true) + { + IJsonWrapper item = ReadValue(factory, reader); + if (item == null && reader.Token == JsonToken.ArrayEnd) + break; + + ((IList)instance).Add(item); + } + } + else if (reader.Token == JsonToken.ObjectStart) + { + instance.SetJsonType(JsonType.Object); + + while (true) + { + reader.Read(); + + if (reader.Token == JsonToken.ObjectEnd) + break; + + string property = (string)reader.Value; + + ((IDictionary)instance)[property] = ReadValue( + factory, reader); + } + + } + + return instance; + } + + private static void ReadSkip(JsonReader reader) + { + ToWrapper( + delegate { return new JsonMockWrapper(); }, reader); + } + + private static void RegisterBaseExporters() + { + base_exporters_table[typeof(byte)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToInt32((byte)obj)); + }; + + base_exporters_table[typeof(char)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToString((char)obj)); + }; + + base_exporters_table[typeof(DateTime)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToString((DateTime)obj, + datetime_format)); + }; + + base_exporters_table[typeof(decimal)] = + delegate (object obj, JsonWriter writer) { + writer.Write((decimal)obj); + }; + + base_exporters_table[typeof(sbyte)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToInt32((sbyte)obj)); + }; + + base_exporters_table[typeof(short)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToInt32((short)obj)); + }; + + base_exporters_table[typeof(ushort)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToInt32((ushort)obj)); + }; + + base_exporters_table[typeof(uint)] = + delegate (object obj, JsonWriter writer) { + writer.Write(Convert.ToUInt64((uint)obj)); + }; + + base_exporters_table[typeof(ulong)] = + delegate (object obj, JsonWriter writer) { + writer.Write((ulong)obj); + }; + + base_exporters_table[typeof(DateTimeOffset)] = + delegate (object obj, JsonWriter writer) { + writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format)); + }; + } + + private static void RegisterBaseImporters() + { + ImporterFunc importer; + + importer = delegate (object input) { + return Convert.ToByte((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(byte), importer); + + importer = delegate (object input) { + return Convert.ToUInt64((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(ulong), importer); + + importer = delegate (object input) { + return Convert.ToInt64((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(long), importer); + + importer = delegate (object input) { + return Convert.ToSByte((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(sbyte), importer); + + importer = delegate (object input) { + return Convert.ToInt16((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(short), importer); + + importer = delegate (object input) { + return Convert.ToUInt16((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(ushort), importer); + + importer = delegate (object input) { + return Convert.ToUInt32((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(uint), importer); + + importer = delegate (object input) { + return Convert.ToSingle((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(float), importer); + + importer = delegate (object input) { + return Convert.ToDouble((int)input); + }; + RegisterImporter(base_importers_table, typeof(int), + typeof(double), importer); + + importer = delegate (object input) { + return Convert.ToDecimal((double)input); + }; + RegisterImporter(base_importers_table, typeof(double), + typeof(decimal), importer); + + importer = delegate (object input) { + return Convert.ToSingle((double)input); + }; + RegisterImporter(base_importers_table, typeof(double), + typeof(float), importer); + + importer = delegate (object input) { + return Convert.ToUInt32((long)input); + }; + RegisterImporter(base_importers_table, typeof(long), + typeof(uint), importer); + + importer = delegate (object input) { + return Convert.ToChar((string)input); + }; + RegisterImporter(base_importers_table, typeof(string), + typeof(char), importer); + + importer = delegate (object input) { + return Convert.ToDateTime((string)input, datetime_format); + }; + RegisterImporter(base_importers_table, typeof(string), + typeof(DateTime), importer); + + importer = delegate (object input) { + return DateTimeOffset.Parse((string)input, datetime_format); + }; + RegisterImporter(base_importers_table, typeof(string), + typeof(DateTimeOffset), importer); + } + + private static void RegisterImporter( + IDictionary> table, + Type json_type, Type value_type, ImporterFunc importer) + { + if (!table.ContainsKey(json_type)) + table.Add(json_type, new Dictionary()); + + table[json_type][value_type] = importer; + } + + private static void WriteValue(object obj, JsonWriter writer, + bool writer_is_private, + int depth) + { + if (depth > max_nesting_depth) + throw new JsonException( + String.Format("Max allowed object depth reached while " + + "trying to export from type {0}", + obj.GetType())); + + if (obj == null) + { + writer.Write(null); + return; + } + + if (obj is IJsonWrapper) + { + if (writer_is_private) + writer.TextWriter.Write(((IJsonWrapper)obj).ToJson()); + else + ((IJsonWrapper)obj).ToJson(writer); + + return; + } + + if (obj is String) + { + writer.Write((string)obj); + return; + } + + if (obj is Double) + { + writer.Write((double)obj); + return; + } + + if (obj is Single) + { + writer.Write((float)obj); + return; + } + + if (obj is Int32) + { + writer.Write((int)obj); + return; + } + + if (obj is Boolean) + { + writer.Write((bool)obj); + return; + } + + if (obj is Int64) + { + writer.Write((long)obj); + return; + } + + if (obj is Array) + { + writer.WriteArrayStart(); + + foreach (object elem in (Array)obj) + WriteValue(elem, writer, writer_is_private, depth + 1); + + writer.WriteArrayEnd(); + + return; + } + + if (obj is IList) + { + writer.WriteArrayStart(); + foreach (object elem in (IList)obj) + WriteValue(elem, writer, writer_is_private, depth + 1); + writer.WriteArrayEnd(); + + return; + } + + if (obj is IDictionary dictionary) + { + writer.WriteObjectStart(); + foreach (DictionaryEntry entry in dictionary) + { + var propertyName = entry.Key is string key ? + key + : Convert.ToString(entry.Key, CultureInfo.InvariantCulture); + writer.WritePropertyName(propertyName); + WriteValue(entry.Value, writer, writer_is_private, + depth + 1); + } + writer.WriteObjectEnd(); + + return; + } + + Type obj_type = obj.GetType(); + + // See if there's a custom exporter for the object + if (custom_exporters_table.ContainsKey(obj_type)) + { + ExporterFunc exporter = custom_exporters_table[obj_type]; + exporter(obj, writer); + + return; + } + + // If not, maybe there's a base exporter + if (base_exporters_table.ContainsKey(obj_type)) + { + ExporterFunc exporter = base_exporters_table[obj_type]; + exporter(obj, writer); + + return; + } + + // Last option, let's see if it's an enum + if (obj is Enum) + { + Type e_type = Enum.GetUnderlyingType(obj_type); + + if (e_type == typeof(long)) + writer.Write((long)obj); + else if (e_type == typeof(uint)) + writer.Write((uint)obj); + else if (e_type == typeof(ulong)) + writer.Write((ulong)obj); + else if (e_type == typeof(ushort)) + writer.Write((ushort)obj); + else if (e_type == typeof(short)) + writer.Write((short)obj); + else if (e_type == typeof(byte)) + writer.Write((byte)obj); + else if (e_type == typeof(sbyte)) + writer.Write((sbyte)obj); + else + writer.Write((int)obj); + + return; + } + + // Okay, so it looks like the input should be exported as an + // object + AddTypeProperties(obj_type); + IList props = type_properties[obj_type]; + + writer.WriteObjectStart(); + foreach (PropertyMetadata p_data in props) + { + if (p_data.IsField) + { + writer.WritePropertyName(p_data.Info.Name); + WriteValue(((FieldInfo)p_data.Info).GetValue(obj), + writer, writer_is_private, depth + 1); + } + else + { + PropertyInfo p_info = (PropertyInfo)p_data.Info; + + if (p_info.CanRead) + { + writer.WritePropertyName(p_data.Info.Name); + WriteValue(p_info.GetValue(obj, null), + writer, writer_is_private, depth + 1); + } + } + } + writer.WriteObjectEnd(); + } + #endregion + + + public static string ToJson(object obj) + { + lock (static_writer_lock) + { + static_writer.Reset(); + + WriteValue(obj, static_writer, true, 0); + + return static_writer.ToString(); + } + } + + public static void ToJson(object obj, JsonWriter writer) + { + WriteValue(obj, writer, false, 0); + } + + public static JsonData ToObject(JsonReader reader) + { + return (JsonData)ToWrapper( + delegate { return new JsonData(); }, reader); + } + + public static JsonData ToObject(TextReader reader) + { + JsonReader json_reader = new JsonReader(reader); + + return (JsonData)ToWrapper( + delegate { return new JsonData(); }, json_reader); + } + + public static JsonData ToObject(string json) + { + return (JsonData)ToWrapper( + delegate { return new JsonData(); }, json); + } + + public static T ToObject(JsonReader reader) + { + return (T)ReadValue(typeof(T), reader); + } + + public static T ToObject(TextReader reader) + { + JsonReader json_reader = new JsonReader(reader); + + return (T)ReadValue(typeof(T), json_reader); + } + + public static T ToObject(string json) + { + JsonReader reader = new JsonReader(json); + + return (T)ReadValue(typeof(T), reader); + } + + public static object ToObject(string json, Type ConvertType) + { + JsonReader reader = new JsonReader(json); + + return ReadValue(ConvertType, reader); + } + + public static IJsonWrapper ToWrapper(WrapperFactory factory, + JsonReader reader) + { + return ReadValue(factory, reader); + } + + public static IJsonWrapper ToWrapper(WrapperFactory factory, + string json) + { + JsonReader reader = new JsonReader(json); + + return ReadValue(factory, reader); + } + + public static void RegisterExporter(ExporterFunc exporter) + { + ExporterFunc exporter_wrapper = + delegate (object obj, JsonWriter writer) { + exporter((T)obj, writer); + }; + + custom_exporters_table[typeof(T)] = exporter_wrapper; + } + + public static void RegisterImporter( + ImporterFunc importer) + { + ImporterFunc importer_wrapper = + delegate (object input) { + return importer((TJson)input); + }; + + RegisterImporter(custom_importers_table, typeof(TJson), + typeof(TValue), importer_wrapper); + } + + public static void UnregisterExporters() + { + custom_exporters_table.Clear(); + } + + public static void UnregisterImporters() + { + custom_importers_table.Clear(); + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/JsonMockWrapper.cs b/src/Cake.Issues.Reporting.Generic/LitJson/JsonMockWrapper.cs new file mode 100644 index 000000000..0671de12f --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/JsonMockWrapper.cs @@ -0,0 +1,115 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * JsonMockWrapper.cs + * Mock object implementing IJsonWrapper, to facilitate actions like + * skipping data more efficiently. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; +using System.Collections; +using System.Collections.Specialized; + + +namespace LitJson +{ + internal class JsonMockWrapper : IJsonWrapper + { + public bool IsArray { get { return false; } } + public bool IsBoolean { get { return false; } } + public bool IsDouble { get { return false; } } + public bool IsInt { get { return false; } } + public bool IsLong { get { return false; } } + public bool IsObject { get { return false; } } + public bool IsString { get { return false; } } + + public bool GetBoolean() { return false; } + public double GetDouble() { return 0.0; } + public int GetInt() { return 0; } + public JsonType GetJsonType() { return JsonType.None; } + public long GetLong() { return 0L; } + public string GetString() { return ""; } + + public void SetBoolean(bool val) { } + public void SetDouble(double val) { } + public void SetInt(int val) { } + public void SetJsonType(JsonType type) { } + public void SetLong(long val) { } + public void SetString(string val) { } + + public string ToJson() { return ""; } + public void ToJson(JsonWriter writer) { } + + + bool IList.IsFixedSize { get { return true; } } + bool IList.IsReadOnly { get { return true; } } + + object IList.this[int index] + { + get { return null; } + set { } + } + + int IList.Add(object value) { return 0; } + void IList.Clear() { } + bool IList.Contains(object value) { return false; } + int IList.IndexOf(object value) { return -1; } + void IList.Insert(int i, object v) { } + void IList.Remove(object value) { } + void IList.RemoveAt(int index) { } + + + int ICollection.Count { get { return 0; } } + bool ICollection.IsSynchronized { get { return false; } } + object ICollection.SyncRoot { get { return null; } } + + void ICollection.CopyTo(Array array, int index) { } + + + IEnumerator IEnumerable.GetEnumerator() { return null; } + + + bool IDictionary.IsFixedSize { get { return true; } } + bool IDictionary.IsReadOnly { get { return true; } } + + ICollection IDictionary.Keys { get { return null; } } + ICollection IDictionary.Values { get { return null; } } + + object IDictionary.this[object key] + { + get { return null; } + set { } + } + + void IDictionary.Add(object k, object v) { } + void IDictionary.Clear() { } + bool IDictionary.Contains(object key) { return false; } + void IDictionary.Remove(object key) { } + + IDictionaryEnumerator IDictionary.GetEnumerator() { return null; } + + + object IOrderedDictionary.this[int idx] + { + get { return null; } + set { } + } + + IDictionaryEnumerator IOrderedDictionary.GetEnumerator() + { + return null; + } + void IOrderedDictionary.Insert(int i, object k, object v) { } + void IOrderedDictionary.RemoveAt(int i) { } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/JsonReader.cs b/src/Cake.Issues.Reporting.Generic/LitJson/JsonReader.cs new file mode 100644 index 000000000..e3457de32 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/JsonReader.cs @@ -0,0 +1,529 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * JsonReader.cs + * Stream-like access to JSON text. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + + +namespace LitJson +{ + internal enum JsonToken + { + None, + + ObjectStart, + PropertyName, + ObjectEnd, + + ArrayStart, + ArrayEnd, + + Int, + Long, + Double, + + String, + + Boolean, + Null + } + + + internal class JsonReader + { + #region Fields + private static readonly IDictionary> parse_table; + + private Stack automaton_stack; + private int current_input; + private int current_symbol; + private bool end_of_json; + private bool end_of_input; + private Lexer lexer; + private bool parser_in_string; + private bool parser_return; + private bool read_started; + private TextReader reader; + private bool reader_is_owned; + private bool skip_non_members; + private object token_value; + private JsonToken token; + #endregion + + + #region Public Properties + public bool AllowComments + { + get { return lexer.AllowComments; } + set { lexer.AllowComments = value; } + } + + public bool AllowSingleQuotedStrings + { + get { return lexer.AllowSingleQuotedStrings; } + set { lexer.AllowSingleQuotedStrings = value; } + } + + public bool SkipNonMembers + { + get { return skip_non_members; } + set { skip_non_members = value; } + } + + public bool EndOfInput + { + get { return end_of_input; } + } + + public bool EndOfJson + { + get { return end_of_json; } + } + + public JsonToken Token + { + get { return token; } + } + + public object Value + { + get { return token_value; } + } + #endregion + + + #region Constructors + static JsonReader() + { + parse_table = PopulateParseTable(); + } + + public JsonReader(string json_text) : + this(new StringReader(json_text), true) + { + } + + public JsonReader(TextReader reader) : + this(reader, false) + { + } + + private JsonReader(TextReader reader, bool owned) + { + if (reader == null) + throw new ArgumentNullException("reader"); + + parser_in_string = false; + parser_return = false; + + read_started = false; + automaton_stack = new Stack(); + automaton_stack.Push((int)ParserToken.End); + automaton_stack.Push((int)ParserToken.Text); + + lexer = new Lexer(reader); + + end_of_input = false; + end_of_json = false; + + skip_non_members = true; + + this.reader = reader; + reader_is_owned = owned; + } + #endregion + + + #region Static Methods + private static IDictionary> PopulateParseTable() + { + // See section A.2. of the manual for details + IDictionary> parse_table = new Dictionary>(); + + TableAddRow(parse_table, ParserToken.Array); + TableAddCol(parse_table, ParserToken.Array, '[', + '[', + (int)ParserToken.ArrayPrime); + + TableAddRow(parse_table, ParserToken.ArrayPrime); + TableAddCol(parse_table, ParserToken.ArrayPrime, '"', + (int)ParserToken.Value, + + (int)ParserToken.ValueRest, + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, '[', + (int)ParserToken.Value, + (int)ParserToken.ValueRest, + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, ']', + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, '{', + (int)ParserToken.Value, + (int)ParserToken.ValueRest, + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.Number, + (int)ParserToken.Value, + (int)ParserToken.ValueRest, + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.True, + (int)ParserToken.Value, + (int)ParserToken.ValueRest, + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.False, + (int)ParserToken.Value, + (int)ParserToken.ValueRest, + ']'); + TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.Null, + (int)ParserToken.Value, + (int)ParserToken.ValueRest, + ']'); + + TableAddRow(parse_table, ParserToken.Object); + TableAddCol(parse_table, ParserToken.Object, '{', + '{', + (int)ParserToken.ObjectPrime); + + TableAddRow(parse_table, ParserToken.ObjectPrime); + TableAddCol(parse_table, ParserToken.ObjectPrime, '"', + (int)ParserToken.Pair, + (int)ParserToken.PairRest, + '}'); + TableAddCol(parse_table, ParserToken.ObjectPrime, '}', + '}'); + + TableAddRow(parse_table, ParserToken.Pair); + TableAddCol(parse_table, ParserToken.Pair, '"', + (int)ParserToken.String, + ':', + (int)ParserToken.Value); + + TableAddRow(parse_table, ParserToken.PairRest); + TableAddCol(parse_table, ParserToken.PairRest, ',', + ',', + (int)ParserToken.Pair, + (int)ParserToken.PairRest); + TableAddCol(parse_table, ParserToken.PairRest, '}', + (int)ParserToken.Epsilon); + + TableAddRow(parse_table, ParserToken.String); + TableAddCol(parse_table, ParserToken.String, '"', + '"', + (int)ParserToken.CharSeq, + '"'); + + TableAddRow(parse_table, ParserToken.Text); + TableAddCol(parse_table, ParserToken.Text, '[', + (int)ParserToken.Array); + TableAddCol(parse_table, ParserToken.Text, '{', + (int)ParserToken.Object); + + TableAddRow(parse_table, ParserToken.Value); + TableAddCol(parse_table, ParserToken.Value, '"', + (int)ParserToken.String); + TableAddCol(parse_table, ParserToken.Value, '[', + (int)ParserToken.Array); + TableAddCol(parse_table, ParserToken.Value, '{', + (int)ParserToken.Object); + TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.Number, + (int)ParserToken.Number); + TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.True, + (int)ParserToken.True); + TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.False, + (int)ParserToken.False); + TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.Null, + (int)ParserToken.Null); + + TableAddRow(parse_table, ParserToken.ValueRest); + TableAddCol(parse_table, ParserToken.ValueRest, ',', + ',', + (int)ParserToken.Value, + (int)ParserToken.ValueRest); + TableAddCol(parse_table, ParserToken.ValueRest, ']', + (int)ParserToken.Epsilon); + + return parse_table; + } + + private static void TableAddCol(IDictionary> parse_table, ParserToken row, int col, + params int[] symbols) + { + parse_table[(int)row].Add(col, symbols); + } + + private static void TableAddRow(IDictionary> parse_table, ParserToken rule) + { + parse_table.Add((int)rule, new Dictionary()); + } + #endregion + + + #region Private Methods + private void ProcessNumber(string number) + { + if (number.IndexOf('.') != -1 || + number.IndexOf('e') != -1 || + number.IndexOf('E') != -1) + { + + double n_double; + if (double.TryParse(number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_double)) + { + token = JsonToken.Double; + token_value = n_double; + + return; + } + } + + int n_int32; + if (int.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int32)) + { + token = JsonToken.Int; + token_value = n_int32; + + return; + } + + long n_int64; + if (long.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int64)) + { + token = JsonToken.Long; + token_value = n_int64; + + return; + } + + ulong n_uint64; + if (ulong.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_uint64)) + { + token = JsonToken.Long; + token_value = n_uint64; + + return; + } + + // Shouldn't happen, but just in case, return something + token = JsonToken.Int; + token_value = 0; + } + + private void ProcessSymbol() + { + if (current_symbol == '[') + { + token = JsonToken.ArrayStart; + parser_return = true; + + } + else if (current_symbol == ']') + { + token = JsonToken.ArrayEnd; + parser_return = true; + + } + else if (current_symbol == '{') + { + token = JsonToken.ObjectStart; + parser_return = true; + + } + else if (current_symbol == '}') + { + token = JsonToken.ObjectEnd; + parser_return = true; + + } + else if (current_symbol == '"') + { + if (parser_in_string) + { + parser_in_string = false; + + parser_return = true; + + } + else + { + if (token == JsonToken.None) + token = JsonToken.String; + + parser_in_string = true; + } + + } + else if (current_symbol == (int)ParserToken.CharSeq) + { + token_value = lexer.StringValue; + + } + else if (current_symbol == (int)ParserToken.False) + { + token = JsonToken.Boolean; + token_value = false; + parser_return = true; + + } + else if (current_symbol == (int)ParserToken.Null) + { + token = JsonToken.Null; + parser_return = true; + + } + else if (current_symbol == (int)ParserToken.Number) + { + ProcessNumber(lexer.StringValue); + + parser_return = true; + + } + else if (current_symbol == (int)ParserToken.Pair) + { + token = JsonToken.PropertyName; + + } + else if (current_symbol == (int)ParserToken.True) + { + token = JsonToken.Boolean; + token_value = true; + parser_return = true; + + } + } + + private bool ReadToken() + { + if (end_of_input) + return false; + + lexer.NextToken(); + + if (lexer.EndOfInput) + { + Close(); + + return false; + } + + current_input = lexer.Token; + + return true; + } + #endregion + + + public void Close() + { + if (end_of_input) + return; + + end_of_input = true; + end_of_json = true; + + if (reader_is_owned) + { + using (reader) { } + } + + reader = null; + } + + public bool Read() + { + if (end_of_input) + return false; + + if (end_of_json) + { + end_of_json = false; + automaton_stack.Clear(); + automaton_stack.Push((int)ParserToken.End); + automaton_stack.Push((int)ParserToken.Text); + } + + parser_in_string = false; + parser_return = false; + + token = JsonToken.None; + token_value = null; + + if (!read_started) + { + read_started = true; + + if (!ReadToken()) + return false; + } + + + int[] entry_symbols; + + while (true) + { + if (parser_return) + { + if (automaton_stack.Peek() == (int)ParserToken.End) + end_of_json = true; + + return true; + } + + current_symbol = automaton_stack.Pop(); + + ProcessSymbol(); + + if (current_symbol == current_input) + { + if (!ReadToken()) + { + if (automaton_stack.Peek() != (int)ParserToken.End) + throw new JsonException( + "Input doesn't evaluate to proper JSON text"); + + if (parser_return) + return true; + + return false; + } + + continue; + } + + try + { + + entry_symbols = + parse_table[current_symbol][current_input]; + + } + catch (KeyNotFoundException e) + { + throw new JsonException((ParserToken)current_input, e); + } + + if (entry_symbols[0] == (int)ParserToken.Epsilon) + continue; + + for (int i = entry_symbols.Length - 1; i >= 0; i--) + automaton_stack.Push(entry_symbols[i]); + } + } + + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/JsonWriter.cs b/src/Cake.Issues.Reporting.Generic/LitJson/JsonWriter.cs new file mode 100644 index 000000000..a5c4ddb1d --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/JsonWriter.cs @@ -0,0 +1,504 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * JsonWriter.cs + * Stream-like facility to output JSON text. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + + +namespace LitJson +{ + internal enum Condition + { + InArray, + InObject, + NotAProperty, + Property, + Value + } + + internal class WriterContext + { + public int Count; + public bool InArray; + public bool InObject; + public bool ExpectingValue; + public int Padding; + } + + internal class JsonWriter + { + #region Fields + private static readonly NumberFormatInfo number_format; + + private WriterContext context; + private Stack ctx_stack; + private bool has_reached_end; + private char[] hex_seq; + private int indentation; + private int indent_value; + private StringBuilder inst_string_builder; + private bool pretty_print; + private bool validate; + private bool lower_case_properties; + private TextWriter writer; + #endregion + + + #region Properties + public int IndentValue + { + get { return indent_value; } + set + { + indentation = (indentation / indent_value) * value; + indent_value = value; + } + } + + public bool PrettyPrint + { + get { return pretty_print; } + set { pretty_print = value; } + } + + public TextWriter TextWriter + { + get { return writer; } + } + + public bool Validate + { + get { return validate; } + set { validate = value; } + } + + public bool LowerCaseProperties + { + get { return lower_case_properties; } + set { lower_case_properties = value; } + } + #endregion + + + #region Constructors + static JsonWriter() + { + number_format = NumberFormatInfo.InvariantInfo; + } + + public JsonWriter() + { + inst_string_builder = new StringBuilder(); + writer = new StringWriter(inst_string_builder); + + Init(); + } + + public JsonWriter(StringBuilder sb) : + this(new StringWriter(sb)) + { + } + + public JsonWriter(TextWriter writer) + { + if (writer == null) + throw new ArgumentNullException("writer"); + + this.writer = writer; + + Init(); + } + #endregion + + + #region Private Methods + private void DoValidation(Condition cond) + { + if (!context.ExpectingValue) + context.Count++; + + if (!validate) + return; + + if (has_reached_end) + throw new JsonException( + "A complete JSON symbol has already been written"); + + switch (cond) + { + case Condition.InArray: + if (!context.InArray) + throw new JsonException( + "Can't close an array here"); + break; + + case Condition.InObject: + if (!context.InObject || context.ExpectingValue) + throw new JsonException( + "Can't close an object here"); + break; + + case Condition.NotAProperty: + if (context.InObject && !context.ExpectingValue) + throw new JsonException( + "Expected a property"); + break; + + case Condition.Property: + if (!context.InObject || context.ExpectingValue) + throw new JsonException( + "Can't add a property here"); + break; + + case Condition.Value: + if (!context.InArray && + (!context.InObject || !context.ExpectingValue)) + throw new JsonException( + "Can't add a value here"); + + break; + } + } + + private void Init() + { + has_reached_end = false; + hex_seq = new char[4]; + indentation = 0; + indent_value = 4; + pretty_print = false; + validate = true; + lower_case_properties = false; + + ctx_stack = new Stack(); + context = new WriterContext(); + ctx_stack.Push(context); + } + + private static void IntToHex(int n, char[] hex) + { + int num; + + for (int i = 0; i < 4; i++) + { + num = n % 16; + + if (num < 10) + hex[3 - i] = (char)('0' + num); + else + hex[3 - i] = (char)('A' + (num - 10)); + + n >>= 4; + } + } + + private void Indent() + { + if (pretty_print) + indentation += indent_value; + } + + + private void Put(string str) + { + if (pretty_print && !context.ExpectingValue) + for (int i = 0; i < indentation; i++) + writer.Write(' '); + + writer.Write(str); + } + + private void PutNewline() + { + PutNewline(true); + } + + private void PutNewline(bool add_comma) + { + if (add_comma && !context.ExpectingValue && + context.Count > 1) + writer.Write(','); + + if (pretty_print && !context.ExpectingValue) + writer.Write(Environment.NewLine); + } + + private void PutString(string str) + { + Put(String.Empty); + + writer.Write('"'); + + int n = str.Length; + for (int i = 0; i < n; i++) + { + switch (str[i]) + { + case '\n': + writer.Write("\\n"); + continue; + + case '\r': + writer.Write("\\r"); + continue; + + case '\t': + writer.Write("\\t"); + continue; + + case '"': + case '\\': + writer.Write('\\'); + writer.Write(str[i]); + continue; + + case '\f': + writer.Write("\\f"); + continue; + + case '\b': + writer.Write("\\b"); + continue; + } + + if ((int)str[i] >= 32 && (int)str[i] <= 126) + { + writer.Write(str[i]); + continue; + } + + // Default, turn into a \uXXXX sequence + IntToHex((int)str[i], hex_seq); + writer.Write("\\u"); + writer.Write(hex_seq); + } + + writer.Write('"'); + } + + private void Unindent() + { + if (pretty_print) + indentation -= indent_value; + } + #endregion + + + public override string ToString() + { + if (inst_string_builder == null) + return String.Empty; + + return inst_string_builder.ToString(); + } + + public void Reset() + { + has_reached_end = false; + + ctx_stack.Clear(); + context = new WriterContext(); + ctx_stack.Push(context); + + if (inst_string_builder != null) + inst_string_builder.Remove(0, inst_string_builder.Length); + } + + public void Write(bool boolean) + { + DoValidation(Condition.Value); + PutNewline(); + + Put(boolean ? "true" : "false"); + + context.ExpectingValue = false; + } + + public void Write(decimal number) + { + DoValidation(Condition.Value); + PutNewline(); + + Put(Convert.ToString(number, number_format)); + + context.ExpectingValue = false; + } + + public void Write(double number) + { + DoValidation(Condition.Value); + PutNewline(); + + string str = Convert.ToString(number, number_format); + Put(str); + + if (str.IndexOf('.') == -1 && + str.IndexOf('E') == -1) + writer.Write(".0"); + + context.ExpectingValue = false; + } + + public void Write(float number) + { + DoValidation(Condition.Value); + PutNewline(); + + string str = Convert.ToString(number, number_format); + Put(str); + + context.ExpectingValue = false; + } + + public void Write(int number) + { + DoValidation(Condition.Value); + PutNewline(); + + Put(Convert.ToString(number, number_format)); + + context.ExpectingValue = false; + } + + public void Write(long number) + { + DoValidation(Condition.Value); + PutNewline(); + + Put(Convert.ToString(number, number_format)); + + context.ExpectingValue = false; + } + + public void Write(string str) + { + DoValidation(Condition.Value); + PutNewline(); + + if (str == null) + Put("null"); + else + PutString(str); + + context.ExpectingValue = false; + } + + public void Write(ulong number) + { + DoValidation(Condition.Value); + PutNewline(); + + Put(Convert.ToString(number, number_format)); + + context.ExpectingValue = false; + } + + public void WriteArrayEnd() + { + DoValidation(Condition.InArray); + PutNewline(false); + + ctx_stack.Pop(); + if (ctx_stack.Count == 1) + has_reached_end = true; + else + { + context = ctx_stack.Peek(); + context.ExpectingValue = false; + } + + Unindent(); + Put("]"); + } + + public void WriteArrayStart() + { + DoValidation(Condition.NotAProperty); + PutNewline(); + + Put("["); + + context = new WriterContext(); + context.InArray = true; + ctx_stack.Push(context); + + Indent(); + } + + public void WriteObjectEnd() + { + DoValidation(Condition.InObject); + PutNewline(false); + + ctx_stack.Pop(); + if (ctx_stack.Count == 1) + has_reached_end = true; + else + { + context = ctx_stack.Peek(); + context.ExpectingValue = false; + } + + Unindent(); + Put("}"); + } + + public void WriteObjectStart() + { + DoValidation(Condition.NotAProperty); + PutNewline(); + + Put("{"); + + context = new WriterContext(); + context.InObject = true; + ctx_stack.Push(context); + + Indent(); + } + + public void WritePropertyName(string property_name) + { + DoValidation(Condition.Property); + PutNewline(); + string propertyName = (property_name == null || !lower_case_properties) + ? property_name + : property_name.ToLowerInvariant(); + + PutString(propertyName); + + if (pretty_print) + { + if (propertyName.Length > context.Padding) + context.Padding = propertyName.Length; + + for (int i = context.Padding - propertyName.Length; + i >= 0; i--) + writer.Write(' '); + + writer.Write(": "); + } + else + writer.Write(':'); + + context.ExpectingValue = true; + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/Lexer.cs b/src/Cake.Issues.Reporting.Generic/LitJson/Lexer.cs new file mode 100644 index 000000000..dda3da955 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/Lexer.cs @@ -0,0 +1,977 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * Lexer.cs + * JSON lexer implementation based on a finite state machine. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + + +namespace LitJson +{ + internal class FsmContext + { + public bool Return; + public int NextState; + public Lexer L; + public int StateStack; + } + + + internal class Lexer + { + #region Fields + private delegate bool StateHandler(FsmContext ctx); + + private static readonly int[] fsm_return_table; + private static readonly StateHandler[] fsm_handler_table; + + private bool allow_comments; + private bool allow_single_quoted_strings; + private bool end_of_input; + private FsmContext fsm_context; + private int input_buffer; + private int input_char; + private TextReader reader; + private int state; + private StringBuilder string_buffer; + private string string_value; + private int token; + private int unichar; + #endregion + + + #region Properties + public bool AllowComments + { + get { return allow_comments; } + set { allow_comments = value; } + } + + public bool AllowSingleQuotedStrings + { + get { return allow_single_quoted_strings; } + set { allow_single_quoted_strings = value; } + } + + public bool EndOfInput + { + get { return end_of_input; } + } + + public int Token + { + get { return token; } + } + + public string StringValue + { + get { return string_value; } + } + #endregion + + + #region Constructors + static Lexer() + { + PopulateFsmTables(out fsm_handler_table, out fsm_return_table); + } + + public Lexer(TextReader reader) + { + allow_comments = true; + allow_single_quoted_strings = true; + + input_buffer = 0; + string_buffer = new StringBuilder(128); + state = 1; + end_of_input = false; + this.reader = reader; + + fsm_context = new FsmContext(); + fsm_context.L = this; + } + #endregion + + + #region Static Methods + private static int HexValue(int digit) + { + switch (digit) + { + case 'a': + case 'A': + return 10; + + case 'b': + case 'B': + return 11; + + case 'c': + case 'C': + return 12; + + case 'd': + case 'D': + return 13; + + case 'e': + case 'E': + return 14; + + case 'f': + case 'F': + return 15; + + default: + return digit - '0'; + } + } + + private static void PopulateFsmTables(out StateHandler[] fsm_handler_table, out int[] fsm_return_table) + { + // See section A.1. of the manual for details of the finite + // state machine. + fsm_handler_table = new StateHandler[28] { + State1, + State2, + State3, + State4, + State5, + State6, + State7, + State8, + State9, + State10, + State11, + State12, + State13, + State14, + State15, + State16, + State17, + State18, + State19, + State20, + State21, + State22, + State23, + State24, + State25, + State26, + State27, + State28 + }; + + fsm_return_table = new int[28] { + (int) ParserToken.Char, + 0, + (int) ParserToken.Number, + (int) ParserToken.Number, + 0, + (int) ParserToken.Number, + 0, + (int) ParserToken.Number, + 0, + 0, + (int) ParserToken.True, + 0, + 0, + 0, + (int) ParserToken.False, + 0, + 0, + (int) ParserToken.Null, + (int) ParserToken.CharSeq, + (int) ParserToken.Char, + 0, + 0, + (int) ParserToken.CharSeq, + (int) ParserToken.Char, + 0, + 0, + 0, + 0 + }; + } + + private static char ProcessEscChar(int esc_char) + { + switch (esc_char) + { + case '"': + case '\'': + case '\\': + case '/': + return Convert.ToChar(esc_char); + + case 'n': + return '\n'; + + case 't': + return '\t'; + + case 'r': + return '\r'; + + case 'b': + return '\b'; + + case 'f': + return '\f'; + + default: + // Unreachable + return '?'; + } + } + + private static bool State1(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') + continue; + + if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 3; + return true; + } + + switch (ctx.L.input_char) + { + case '"': + ctx.NextState = 19; + ctx.Return = true; + return true; + + case ',': + case ':': + case '[': + case ']': + case '{': + case '}': + ctx.NextState = 1; + ctx.Return = true; + return true; + + case '-': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 2; + return true; + + case '0': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 4; + return true; + + case 'f': + ctx.NextState = 12; + return true; + + case 'n': + ctx.NextState = 16; + return true; + + case 't': + ctx.NextState = 9; + return true; + + case '\'': + if (!ctx.L.allow_single_quoted_strings) + return false; + + ctx.L.input_char = '"'; + ctx.NextState = 23; + ctx.Return = true; + return true; + + case '/': + if (!ctx.L.allow_comments) + return false; + + ctx.NextState = 25; + return true; + + default: + return false; + } + } + + return true; + } + + private static bool State2(FsmContext ctx) + { + ctx.L.GetChar(); + + if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 3; + return true; + } + + switch (ctx.L.input_char) + { + case '0': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 4; + return true; + + default: + return false; + } + } + + private static bool State3(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + continue; + } + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') + { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) + { + case ',': + case ']': + case '}': + ctx.L.UngetChar(); + ctx.Return = true; + ctx.NextState = 1; + return true; + + case '.': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 5; + return true; + + case 'e': + case 'E': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 7; + return true; + + default: + return false; + } + } + return true; + } + + private static bool State4(FsmContext ctx) + { + ctx.L.GetChar(); + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') + { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) + { + case ',': + case ']': + case '}': + ctx.L.UngetChar(); + ctx.Return = true; + ctx.NextState = 1; + return true; + + case '.': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 5; + return true; + + case 'e': + case 'E': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 7; + return true; + + default: + return false; + } + } + + private static bool State5(FsmContext ctx) + { + ctx.L.GetChar(); + + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 6; + return true; + } + + return false; + } + + private static bool State6(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + continue; + } + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') + { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) + { + case ',': + case ']': + case '}': + ctx.L.UngetChar(); + ctx.Return = true; + ctx.NextState = 1; + return true; + + case 'e': + case 'E': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 7; + return true; + + default: + return false; + } + } + + return true; + } + + private static bool State7(FsmContext ctx) + { + ctx.L.GetChar(); + + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 8; + return true; + } + + switch (ctx.L.input_char) + { + case '+': + case '-': + ctx.L.string_buffer.Append((char)ctx.L.input_char); + ctx.NextState = 8; + return true; + + default: + return false; + } + } + + private static bool State8(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') + { + ctx.L.string_buffer.Append((char)ctx.L.input_char); + continue; + } + + if (ctx.L.input_char == ' ' || + ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') + { + ctx.Return = true; + ctx.NextState = 1; + return true; + } + + switch (ctx.L.input_char) + { + case ',': + case ']': + case '}': + ctx.L.UngetChar(); + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + return true; + } + + private static bool State9(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'r': + ctx.NextState = 10; + return true; + + default: + return false; + } + } + + private static bool State10(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'u': + ctx.NextState = 11; + return true; + + default: + return false; + } + } + + private static bool State11(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'e': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State12(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'a': + ctx.NextState = 13; + return true; + + default: + return false; + } + } + + private static bool State13(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'l': + ctx.NextState = 14; + return true; + + default: + return false; + } + } + + private static bool State14(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 's': + ctx.NextState = 15; + return true; + + default: + return false; + } + } + + private static bool State15(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'e': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State16(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'u': + ctx.NextState = 17; + return true; + + default: + return false; + } + } + + private static bool State17(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'l': + ctx.NextState = 18; + return true; + + default: + return false; + } + } + + private static bool State18(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'l': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State19(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + switch (ctx.L.input_char) + { + case '"': + ctx.L.UngetChar(); + ctx.Return = true; + ctx.NextState = 20; + return true; + + case '\\': + ctx.StateStack = 19; + ctx.NextState = 21; + return true; + + default: + ctx.L.string_buffer.Append((char)ctx.L.input_char); + continue; + } + } + + return true; + } + + private static bool State20(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case '"': + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State21(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case 'u': + ctx.NextState = 22; + return true; + + case '"': + case '\'': + case '/': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + ctx.L.string_buffer.Append( + ProcessEscChar(ctx.L.input_char)); + ctx.NextState = ctx.StateStack; + return true; + + default: + return false; + } + } + + private static bool State22(FsmContext ctx) + { + int counter = 0; + int mult = 4096; + + ctx.L.unichar = 0; + + while (ctx.L.GetChar()) + { + + if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' || + ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' || + ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') + { + + ctx.L.unichar += HexValue(ctx.L.input_char) * mult; + + counter++; + mult /= 16; + + if (counter == 4) + { + ctx.L.string_buffer.Append( + Convert.ToChar(ctx.L.unichar)); + ctx.NextState = ctx.StateStack; + return true; + } + + continue; + } + + return false; + } + + return true; + } + + private static bool State23(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + switch (ctx.L.input_char) + { + case '\'': + ctx.L.UngetChar(); + ctx.Return = true; + ctx.NextState = 24; + return true; + + case '\\': + ctx.StateStack = 23; + ctx.NextState = 21; + return true; + + default: + ctx.L.string_buffer.Append((char)ctx.L.input_char); + continue; + } + } + + return true; + } + + private static bool State24(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case '\'': + ctx.L.input_char = '"'; + ctx.Return = true; + ctx.NextState = 1; + return true; + + default: + return false; + } + } + + private static bool State25(FsmContext ctx) + { + ctx.L.GetChar(); + + switch (ctx.L.input_char) + { + case '*': + ctx.NextState = 27; + return true; + + case '/': + ctx.NextState = 26; + return true; + + default: + return false; + } + } + + private static bool State26(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char == '\n') + { + ctx.NextState = 1; + return true; + } + } + + return true; + } + + private static bool State27(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char == '*') + { + ctx.NextState = 28; + return true; + } + } + + return true; + } + + private static bool State28(FsmContext ctx) + { + while (ctx.L.GetChar()) + { + if (ctx.L.input_char == '*') + continue; + + if (ctx.L.input_char == '/') + { + ctx.NextState = 1; + return true; + } + + ctx.NextState = 27; + return true; + } + + return true; + } + #endregion + + + private bool GetChar() + { + if ((input_char = NextChar()) != -1) + return true; + + end_of_input = true; + return false; + } + + private int NextChar() + { + if (input_buffer != 0) + { + int tmp = input_buffer; + input_buffer = 0; + + return tmp; + } + + return reader.Read(); + } + + public bool NextToken() + { + StateHandler handler; + fsm_context.Return = false; + + while (true) + { + handler = fsm_handler_table[state - 1]; + + if (!handler(fsm_context)) + throw new JsonException(input_char); + + if (end_of_input) + return false; + + if (fsm_context.Return) + { + string_value = string_buffer.ToString(); + string_buffer.Remove(0, string_buffer.Length); + token = fsm_return_table[state - 1]; + + if (token == (int)ParserToken.Char) + token = input_char; + + state = fsm_context.NextState; + + return true; + } + + state = fsm_context.NextState; + } + } + + private void UngetChar() + { + input_buffer = input_char; + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/LitJson/ParserToken.cs b/src/Cake.Issues.Reporting.Generic/LitJson/ParserToken.cs new file mode 100644 index 000000000..85dd10da3 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/LitJson/ParserToken.cs @@ -0,0 +1,49 @@ +#pragma warning disable 1587 +#pragma warning disable 1591 + +#region Header +/** + * ParserToken.cs + * Internal representation of the tokens used by the lexer and the parser. + * + * The authors disclaim copyright to this source code. For more details, see + * the 3rd-Party-License.md file included with this distribution. + **/ + +// This file isn't generated, but this comment is necessary to exclude it from code analysis. +// +#endregion + +namespace LitJson +{ + internal enum ParserToken + { + // Lexer tokens (see section A.1.1. of the manual) + None = System.Char.MaxValue + 1, + Number, + True, + False, + Null, + CharSeq, + // Single char + Char, + + // Parser Rules (see section A.2.1 of the manual) + Text, + Object, + ObjectPrime, + Pair, + PairRest, + Array, + ArrayPrime, + Value, + ValueRest, + String, + + // End of input + End, + + // The empty rule + Epsilon + } +} diff --git a/src/Cake.Issues.Reporting.Generic/Properties/ProjectInfo.cs b/src/Cake.Issues.Reporting.Generic/Properties/ProjectInfo.cs new file mode 100644 index 000000000..62d42a448 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/Properties/ProjectInfo.cs @@ -0,0 +1,14 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b514788a-8596-41ca-92b6-86199549dc2a")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.Reporting.Generic.Tests")] \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/ReportColumn.cs b/src/Cake.Issues.Reporting.Generic/ReportColumn.cs new file mode 100644 index 000000000..2b28de9f9 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/ReportColumn.cs @@ -0,0 +1,106 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Name of columns in a report. + /// The value can be used for default positions of the columns. + /// + public enum ReportColumn + { + /// + /// Column for the field. + /// + ProviderType = 100, + + /// + /// Column for the field. + /// + ProviderName = 200, + + /// + /// Column for the field. + /// + Priority = 300, + + /// + /// Column for the field. + /// + PriorityName = 400, + + /// + /// Column for the field. + /// + ProjectPath = 500, + + /// + /// Column for the field. + /// + ProjectName = 600, + + /// + /// Column for the field. + /// + FilePath = 700, + + /// + /// Column for the value returned by . + /// + FileDirectory = 800, + + /// + /// Column for the value returned by . + /// + FileName = 900, + + /// + /// Column for the field. + /// + Line = 1000, + + /// + /// Column for the field. + /// + EndLine = 1010, + + /// + /// Column for the field. + /// + Column = 1020, + + /// + /// Column for the field. + /// + EndColumn = 1030, + + /// + /// Column for the value returned by . + /// + Location = 1050, + + /// + /// Column for the field. + /// + RuleId = 1100, + + /// + /// Column for the field. + /// + RuleName = 1110, + + /// + /// Column for the field. + /// + RuleUrl = 1200, + + /// + /// Column for the message. This can either be the , + /// or field, + /// depending on the report. + /// + Message = 1300, + + /// + /// Column for the field. + /// + Run = 1400, + } +} diff --git a/src/Cake.Issues.Reporting.Generic/StringExtensions.cs b/src/Cake.Issues.Reporting.Generic/StringExtensions.cs new file mode 100644 index 000000000..70112bcae --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/StringExtensions.cs @@ -0,0 +1,50 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System.Text.RegularExpressions; + + /// + /// Extensions for . + /// + public static class StringExtensions + { + /// + /// Sanitizes a string to be a valid HTML ID. + /// + /// String which should be sanitized. + /// as valid HTML ID. + public static string SanitizeHtmlIdAttribute(this string input) + { + if (string.IsNullOrWhiteSpace(input)) + { + return string.Empty; + } + + // Cutoff illegal characters in the beginning + var firstLegalCharacter = GetIndexOfFirstLetter(input); + input = input.Substring(firstLegalCharacter); + + return Regex.Replace(input, @"/^[^a-z]+|[^\w:-]+", "-"); + } + + /// + /// Returns the index of the first letter in a string. + /// + /// String to search for a letter. + /// Index of the first letter in . + private static int GetIndexOfFirstLetter(string input) + { + var index = 0; + foreach (var c in input) + { + if (char.IsLetter(c)) + { + return index; + } + + index++; + } + + return input.Length; + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/Templates/DataTable.cshtml b/src/Cake.Issues.Reporting.Generic/Templates/DataTable.cshtml new file mode 100644 index 000000000..937283e81 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/Templates/DataTable.cshtml @@ -0,0 +1,116 @@ +@inherits IEnumerable + +@using System.Collections.Generic +@using System.Linq +@using Cake.Issues +@using Cake.Issues.Reporting.Generic + + + + + + + Issues Report + @*! + * + * Simple-DataTables + * https://github.com/fiduswriter/Simple-DataTables + * Licensed under LGPL (https://github.com/fiduswriter/Simple-DataTables/blob/main/LICENSE) + * + * Version 4.0.8 + *@ + + + + + + + +

    Issues Report

    + + @{ + var groupedIssues = + from issue in Model + group issue by new { issue.ProviderType, issue.Run }; + } + + @foreach (var group in groupedIssues) + { + var title = group.First().ProviderName; + var tableId = group.Key.ProviderType; + + if (!string.IsNullOrWhiteSpace(group.Key.Run)) + { + title += " - " + group.Key.Run; + tableId += group.Key.Run; + } + + tableId = tableId.SanitizeHtmlIdAttribute(); + + if (groupedIssues.Count() > 1) + { +

    @title

    + } + + + + + + + + + + + + + + + @foreach (var issue in group.OrderByDescending(x => x.Priority)) + { + + + + + + + + + + } + +
    SeverityProjectDirectoryFileLocationRuleMessage
    @issue.PriorityName@issue.ProjectName@issue.FileDirectory()@issue.FileName()@issue.LineRange() + @if (issue.RuleUrl != null) + { + @issue.RuleId + } + else + { + @issue.RuleId; + } + @issue.MessageText
    + + } + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/Templates/Diagnostic.cshtml b/src/Cake.Issues.Reporting.Generic/Templates/Diagnostic.cshtml new file mode 100644 index 000000000..6714fd6eb --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/Templates/Diagnostic.cshtml @@ -0,0 +1,64 @@ +@inherits IEnumerable + +@using System.Collections.Generic +@using System.Linq + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @foreach (var issue in Model) + { + + + + + + + + + + + + + + + + + + + + + } + +
    ProjectFileRelativePathProjectNameAffectedFileRelativePathLineEndLineColumnEndColumnMessageTextMessageHtmlMessageMarkdownPriorityPriorityNameRuleIdRuleNameRuleUrlRunProviderTypeProviderName
    @issue.ProjectFileRelativePath@issue.ProjectName@issue.AffectedFileRelativePath@issue.Line@issue.EndLine@issue.Column@issue.EndColumn@issue.MessageText@issue.MessageHtml@issue.MessageMarkdown@issue.Priority@issue.PriorityName@issue.RuleId@issue.RuleName@issue.RuleUrl@issue.Run@issue.ProviderType@issue.ProviderName
    + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/Templates/DxDataGrid.cshtml b/src/Cake.Issues.Reporting.Generic/Templates/DxDataGrid.cshtml new file mode 100644 index 000000000..5e71300b4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/Templates/DxDataGrid.cshtml @@ -0,0 +1,800 @@ +@inherits IEnumerable + +@using System.Collections.Generic +@using System.Linq +@using Cake.Issues +@using Cake.Issues.Serialization +@using Cake.Issues.Reporting.Generic + + + +@{ + // Read options and apply default values. + var title = ViewBagHelper.ValueOrDefault(ViewBag.Title, "Issues Report"); + DevExtremeTheme theme = ViewBagHelper.ValueOrDefault(ViewBag.Theme, DevExtremeTheme.Light); + bool showHeader = ViewBagHelper.ValueOrDefault(ViewBag.ShowHeader, true); + bool enableSearching = ViewBagHelper.ValueOrDefault(ViewBag.EnableSearching, true); + bool enableGrouping = ViewBagHelper.ValueOrDefault(ViewBag.EnableGrouping, true); + bool enableFiltering = ViewBagHelper.ValueOrDefault(ViewBag.EnableFiltering, true); + bool enableExporting = ViewBagHelper.ValueOrDefault(ViewBag.EnableExporting, false); + string exportFileName = ViewBagHelper.ValueOrDefault(ViewBag.ExportFileName, "issue-report"); + HtmlDxDataGridExportFormat exportFormat = ViewBagHelper.ValueOrDefault(ViewBag.ExportFormat, HtmlDxDataGridExportFormat.Excel); + bool providerTypeVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeVisible, false); + ColumnSortOrder providerTypeSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProviderTypeSortOder, ColumnSortOrder.Ascending); + bool providerNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameVisible, true); + ColumnSortOrder providerNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProviderNameSortOder, ColumnSortOrder.Ascending); + bool runVisible = ViewBagHelper.ValueOrDefault(ViewBag.RunVisible, Model.Any(x => !string.IsNullOrWhiteSpace(x.Run))); + ColumnSortOrder runSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RunSortOder, ColumnSortOrder.Ascending); + bool priorityVisible = ViewBagHelper.ValueOrDefault(ViewBag.PriorityVisible, false); + ColumnSortOrder prioritySortOrder = ViewBagHelper.ValueOrDefault(ViewBag.PrioritySortOrder, ColumnSortOrder.Descending); + bool priorityNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameVisible, true); + ColumnSortOrder priorityNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.PriorityNameSortOrder, ColumnSortOrder.Descending); + bool projectPathVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathVisible, false); + ColumnSortOrder projectPathSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProjectPathSortOder, ColumnSortOrder.Ascending); + bool projectNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameVisible, true); + ColumnSortOrder projectNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ProjectNameSortOder, ColumnSortOrder.Ascending); + bool filePathVisible = ViewBagHelper.ValueOrDefault(ViewBag.FilePathVisible, false); + ColumnSortOrder filePathSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FilePathSortOder, ColumnSortOrder.Ascending); + bool fileDirectoryVisible = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectoryVisible, true); + ColumnSortOrder fileDirectorySortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FileDirectorySortOder, ColumnSortOrder.Ascending); + bool fileNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.FileNameVisible, true); + ColumnSortOrder fileNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.FileNameSortOder, ColumnSortOrder.Ascending); + bool lineVisible = ViewBagHelper.ValueOrDefault(ViewBag.LineVisible, false); + ColumnSortOrder lineSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.LineSortOder, ColumnSortOrder.Ascending); + bool endLineVisible = ViewBagHelper.ValueOrDefault(ViewBag.EndLineVisible, false); + ColumnSortOrder endLineSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.EndLineSortOder, ColumnSortOrder.Ascending); + bool columnVisible = ViewBagHelper.ValueOrDefault(ViewBag.ColumnVisible, false); + ColumnSortOrder columnSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.ColumnSortOder, ColumnSortOrder.Ascending); + bool endColumnVisible = ViewBagHelper.ValueOrDefault(ViewBag.EndColumnVisible, false); + ColumnSortOrder endColumnSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.EndColumnSortOder, ColumnSortOrder.Ascending); + bool locationVisible = ViewBagHelper.ValueOrDefault(ViewBag.LocationVisible, true); + ColumnSortOrder locationSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.LocationSortOder, ColumnSortOrder.Ascending); + bool ruleIdVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleIdVisible, true); + ColumnSortOrder ruleIdSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleIdSortOder, ColumnSortOrder.Ascending); + bool ruleNameVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleNameVisible, true); + ColumnSortOrder ruleNameSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleNameSortOder, ColumnSortOrder.Ascending); + bool ruleUrlVisible = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlVisible, false); + ColumnSortOrder ruleUrlSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.RuleUrlSortOder, ColumnSortOrder.Ascending); + bool messageVisible = ViewBagHelper.ValueOrDefault(ViewBag.MessageVisible, true); + ColumnSortOrder messageSortOrder = ViewBagHelper.ValueOrDefault(ViewBag.MessageSortOder, ColumnSortOrder.Ascending); + var groupedColumns = ViewBagHelper.ValueOrDefault(ViewBag.GroupedColumns, new List { ReportColumn.ProviderName, ReportColumn.Run }); + var sortedColumns = ViewBagHelper.ValueOrDefault(ViewBag.SortedColumns, new List { ReportColumn.PriorityName, ReportColumn.ProjectName, ReportColumn.FileDirectory, ReportColumn.FileName, ReportColumn.Line }); + IdeIntegrationSettings ideIntegrationSettings = ViewBagHelper.ValueOrDefault(ViewBag.IdeIntegrationSettings, null); + List additionalColumns = ViewBagHelper.ValueOrDefault(ViewBag.AdditionalColumns, new List()); + string jQueryLocation = ViewBagHelper.ValueOrDefault(ViewBag.JQueryLocation, "https://ajax.aspnetcdn.com/ajax/jquery/").Trim(); + jQueryLocation = jQueryLocation.WithEnding("/"); + string jQueryVersion = ViewBagHelper.ValueOrDefault(ViewBag.JQueryVersion, "3.7.0").Trim(); + string excelJsLocation = ViewBagHelper.ValueOrDefault(ViewBag.ExcelJsLocation, "https://cdnjs.cloudflare.com/ajax/libs/exceljs/").Trim(); + excelJsLocation = excelJsLocation.WithEnding("/"); + string excelJsVersion = ViewBagHelper.ValueOrDefault(ViewBag.ExcelJsVersion, "4.4.0").Trim(); + string filesaverJsLocation = ViewBagHelper.ValueOrDefault(ViewBag.FileSaverJsLocation, "https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/").Trim(); + filesaverJsLocation = filesaverJsLocation.WithEnding("/"); + string filesaverJsVersion = ViewBagHelper.ValueOrDefault(ViewBag.FileSaverJsVersion, "2.0.5").Trim(); + string jsPdfLocation = ViewBagHelper.ValueOrDefault(ViewBag.JsPdfLocation, "https://cdnjs.cloudflare.com/ajax/libs/jspdf/").Trim(); + jsPdfLocation = jsPdfLocation.WithEnding("/"); + string jsPdfVersion = ViewBagHelper.ValueOrDefault(ViewBag.FileSaverJsVersion, "2.5.1").Trim(); + string jsPdfAutoTableLocation = ViewBagHelper.ValueOrDefault(ViewBag.FileSaverJsLocation, "https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/").Trim(); + jsPdfAutoTableLocation = jsPdfAutoTableLocation.WithEnding("/"); + string jsPdfAutoTableVersion = ViewBagHelper.ValueOrDefault(ViewBag.FileSaverJsVersion, "3.8.2").Trim(); + string devExtremeLocation = ViewBagHelper.ValueOrDefault(ViewBag.DevExtremeLocation, "https://cdn3.devexpress.com/jslib/").Trim(); + devExtremeLocation = devExtremeLocation.WithEnding("/"); + string devExtremeVersion = ViewBagHelper.ValueOrDefault(ViewBag.DevExtremeVersion, "23.1.6").Trim(); +} + +@{ + // Prepare issues. + var issues = + from issue in Model + select + issue.GetExpandoObject( + addProviderType: providerTypeVisible, + addProviderName: providerNameVisible, + addRun: runVisible, + addPriority: priorityVisible || priorityNameVisible, + addPriorityName: priorityNameVisible, + addProjectPath: projectPathVisible, + addProjectName: projectNameVisible, + addFilePath: filePathVisible || ideIntegrationSettings != null, + addFileDirectory: fileDirectoryVisible, + addFileName: fileNameVisible, + addFileLink: true, + addLine: lineVisible || ideIntegrationSettings != null, + addEndLine: endLineVisible || ideIntegrationSettings != null, + addColumn: columnVisible || ideIntegrationSettings != null, + addEndColumn: endColumnVisible || ideIntegrationSettings != null, + addLocation: locationVisible, + addRuleId: ruleIdVisible, + addRuleName: ruleNameVisible, + addRuleUrl: ruleIdVisible || ruleNameVisible || ruleUrlVisible, + addMessageHtml: messageVisible, + additionalValues: additionalColumns.ToDictionary(x => x.Id, x => x.ValueRetriever)); +} + + + + + @title + + @* DevExtreme dependencies *@ + + @if (enableExporting) + { + @switch (exportFormat) + { + case HtmlDxDataGridExportFormat.Excel: + + + break; + case HtmlDxDataGridExportFormat.Pdf: + + + break; + } + } + @* DevExtreme themes *@ + + + @* DevExtreme library *@ + + @* Additional JavaScript for IDE integration *@ + @if (ideIntegrationSettings != null && !string.IsNullOrWhiteSpace(ideIntegrationSettings.JavaScript)) + { + + } + + + + + @if (showHeader) + { +

    @title

    + } + +
    +
    +
    + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Generic/UriExtensions.cs b/src/Cake.Issues.Reporting.Generic/UriExtensions.cs new file mode 100644 index 000000000..5af4f7173 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/UriExtensions.cs @@ -0,0 +1,36 @@ +namespace Cake.Issues.Reporting.Generic +{ + using System; + using System.Globalization; + using System.Linq; + + /// + /// Extensions for the class. + /// + internal static class UriExtensions + { + /// + /// Appends paths to an URI. + /// + /// URI to which the paths should be appended. + /// Paths to append. + /// URI with appended paths. + public static Uri Append(this Uri uri, params string[] paths) + { + uri.NotNull(nameof(uri)); + + return + new Uri( + paths + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Aggregate( + uri.AbsoluteUri, + (current, path) => + string.Format( + CultureInfo.InvariantCulture, + "{0}/{1}", + current.TrimEnd('/'), + path.TrimStart('/')))); + } + } +} diff --git a/src/Cake.Issues.Reporting.Generic/ViewBagHelper.cs b/src/Cake.Issues.Reporting.Generic/ViewBagHelper.cs new file mode 100644 index 000000000..a251d3587 --- /dev/null +++ b/src/Cake.Issues.Reporting.Generic/ViewBagHelper.cs @@ -0,0 +1,25 @@ +namespace Cake.Issues.Reporting.Generic +{ + /// + /// Helper for working with the ViewBag in templates. + /// + public static class ViewBagHelper + { + /// + /// Returns the value or a default value if is null. + /// + /// Type of the value. + /// Value which should be returned. + /// Value which should be returned if is null. + /// or if is null. + public static T ValueOrDefault(object value, T defaultValue) + { + if (value != null) + { + return (T)value; + } + + return defaultValue; + } + } +} diff --git a/src/Cake.Issues.Reporting.Sarif.Tests/Cake.Issues.Reporting.Sarif.Tests.csproj b/src/Cake.Issues.Reporting.Sarif.Tests/Cake.Issues.Reporting.Sarif.Tests.csproj new file mode 100644 index 000000000..c347bf51d --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif.Tests/Cake.Issues.Reporting.Sarif.Tests.csproj @@ -0,0 +1,43 @@ + + + + Library + net6.0 + false + Tests for the Cake.Issues.Reporting.Sarif addin + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + ..\Cake.Issues.Tests.ruleset + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + + 2.5.8 + runtime; build; native; contentfiles; analyzers + all + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Sarif.Tests/Properties/ProjectInfo.cs b/src/Cake.Issues.Reporting.Sarif.Tests/Properties/ProjectInfo.cs new file mode 100644 index 000000000..3a33d3fb7 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif.Tests/Properties/ProjectInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1634d785-eac1-4e1c-ba92-439508463b8f")] diff --git a/src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportFixture.cs b/src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportFixture.cs new file mode 100644 index 000000000..b08557cd5 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportFixture.cs @@ -0,0 +1,77 @@ +namespace Cake.Issues.Reporting.Sarif.Tests +{ + using System; + using System.Collections.Generic; + using System.IO; + using Cake.Core.Diagnostics; + using Cake.Testing; + using Shouldly; + + internal class SarifIssueReportFixture + { + public const string RepositoryRootPath = @"c:\Source\Cake.Issues.Reporting.Sarif"; + + public SarifIssueReportFixture() + { + this.Log = new FakeLog { Verbosity = Verbosity.Normal }; + this.SarifIssueReportFormatSettings = new SarifIssueReportFormatSettings(); + } + + public FakeLog Log { get; set; } + + public SarifIssueReportFormatSettings SarifIssueReportFormatSettings { get; set; } + + public string CreateReport(IEnumerable issues) + { + var generator = + new SarifIssueReportGenerator(this.Log, this.SarifIssueReportFormatSettings); + + var reportFile = Path.GetTempFileName(); + try + { + var createIssueReportSettings = + new CreateIssueReportSettings(RepositoryRootPath, reportFile); + generator.Initialize(createIssueReportSettings); + generator.CreateReport(issues); + + using (var stream = new FileStream(reportFile, FileMode.Open, FileAccess.Read)) + { + using (var sr = new StreamReader(stream)) + { + return sr.ReadToEnd(); + } + } + } + finally + { + if (File.Exists(reportFile)) + { + File.Delete(reportFile); + } + } + } + + public void TestReportCreation(Action settings) + { + // Given + settings(this.SarifIssueReportFormatSettings); + + // When + var result = + this.CreateReport( + new List + { + IssueBuilder + .NewIssue("Message Foo", "ProviderType Foo", "ProviderName Foo") + .InFile(@"src\Cake.Issues.Reporting.Generic.Tests\Foo.cs", 10) + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Warning) + .Create(), + }); + + // Then + // Currently only checks if genertions failed or not without checking actual output. + result.ShouldNotBeNull(); + } + } +} diff --git a/src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs b/src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs new file mode 100644 index 000000000..7e36297e9 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs @@ -0,0 +1,166 @@ +namespace Cake.Issues.Reporting.Sarif.Tests +{ + using System; + using System.Collections.Generic; + using Cake.Issues.Testing; + using Cake.Testing; + using Microsoft.CodeAnalysis.Sarif; + using Newtonsoft.Json; + using Shouldly; + using Xunit; + + public sealed class SarifIssueReportGeneratorTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => + new SarifIssueReportGenerator( + null, + new SarifIssueReportFormatSettings())); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given / When + var result = Record.Exception(() => + new SarifIssueReportGenerator( + new FakeLog(), + null)); + + // Then + result.IsArgumentNullException("settings"); + } + } + + public sealed class TheInternalCreateReportMethod + { + [Fact] + public void Should_Generate_Report() + { + // Given + var fixture = new SarifIssueReportFixture(); + var issues = + new List + { + IssueBuilder + .NewIssue("Message Foo.", "ProviderType Foo", "ProviderName Foo") + .InFile(@"src\Cake.Issues.Reporting.Sarif.Tests\SarifIssueReportGeneratorTests.cs", 10) + .InProjectFile(@"src\Cake.Issues.Reporting.Sarif.Tests\Cake.Issues.Reporting.Sarif.Tests.csproj") + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Error) + .Create(), + + // Issue to exercise creation of rule metadata with helpUri, and messages + // in Markdown format. + IssueBuilder + .NewIssue("Message Bar.", "ProviderType Bar", "ProviderName Bar") + .InFile(@"src\Cake.Issues.Reporting.Sarif.Tests\SarifIssueReportGeneratorTests.cs", 12, 5) + .OfRule("Rule Bar", new Uri("https://www.example.come/rules/bar.html")) + .WithPriority(IssuePriority.Warning) + .WithMessageInMarkdownFormat("Message Bar -- now in **Markdown**!") + .Create(), + + // Issue to exercise the corner case where ruleId is absent (so no rule + // metadata is created) but helpUri is present (so it is stored in the + // result's property bag. + IssueBuilder + .NewIssue("Message Bar 2.", "ProviderType Bar", "ProviderName Bar") + .InFile(@"src\Cake.Issues.Reporting.Sarif.Tests\SarifIssueReportGeneratorTests.cs", 23, 42, 5, 10) + .OfRule(null, new Uri("https://www.example.come/rules/bar2.html")) + .WithPriority(IssuePriority.Warning) + .Create(), + }; + + // When + var logContents = fixture.CreateReport(issues); + + // Then + var sarifLog = JsonConvert.DeserializeObject(logContents); + + // There are two runs because there are two issue providers. + sarifLog.Runs.Count.ShouldBe(2); + + Run run = sarifLog.Runs[0]; + run.Tool.Driver.Name.ShouldBe("ProviderType Foo"); + + // This run doesn't have any rules that specify a help URI, so we didn't bother + // adding rule metadata. + run.Tool.Driver.Rules.ShouldBeNull(); + + run.Results.Count.ShouldBe(1); + + Result result = run.Results[0]; + result.RuleId.ShouldBe("Rule Foo"); + result.RuleIndex.ShouldBe(-1); // because there's no rule metadata to point to. + result.Message.Text.ShouldBe("Message Foo."); + result.Message.Markdown.ShouldBeNull(); + result.Level.ShouldBe(FailureLevel.Error); + result.Kind.ShouldBe(ResultKind.Fail); + + result.Locations.Count.ShouldBe(1); + PhysicalLocation physicalLocation = result.Locations[0].PhysicalLocation; + physicalLocation.ArtifactLocation.Uri.OriginalString.ShouldBe("src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs"); + physicalLocation.Region.StartLine.ShouldBe(10); + + run.OriginalUriBaseIds.Count.ShouldBe(1); + run.OriginalUriBaseIds[SarifIssueReportGenerator.RepoRootUriBaseId].Uri.LocalPath.ShouldBe(SarifIssueReportFixture.RepositoryRootPath); + + run = sarifLog.Runs[1]; + run.Tool.Driver.Name.ShouldBe("ProviderType Bar"); + + // This run has a rule that specifies a help URI, so we added rule metadata. + IList rules = run.Tool.Driver.Rules; + rules.Count.ShouldBe(1); + + ReportingDescriptor rule = rules[0]; + rule.Id.ShouldBe("Rule Bar"); + rule.HelpUri.OriginalString.ShouldBe("https://www.example.come/rules/bar.html"); + + run.Results.Count.ShouldBe(2); + + result = run.Results[0]; + result.RuleId.ShouldBe("Rule Bar"); + result.RuleIndex.ShouldBe(0); // The index of the metadata for this rule in the rules array. + result.Message.Text.ShouldBe("Message Bar."); + result.Message.Markdown.ShouldBe("Message Bar -- now in **Markdown**!"); + result.Level.ShouldBe(FailureLevel.Warning); + result.Kind.ShouldBe(ResultKind.Fail); + + result.Locations.Count.ShouldBe(1); + physicalLocation = result.Locations[0].PhysicalLocation; + physicalLocation.ArtifactLocation.Uri.OriginalString.ShouldBe("src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs"); + physicalLocation.Region.StartLine.ShouldBe(12); + physicalLocation.Region.StartColumn.ShouldBe(5); + + // This run also includes an issue with a rule URL but no rule name, so we'll find + // the rule URL in the result's property bag. + result = run.Results[1]; + result.RuleId.ShouldBeNull(); + result.RuleIndex.ShouldBe(-1); + result.GetProperty(SarifIssueReportGenerator.RuleUrlPropertyName).ShouldBe("https://www.example.come/rules/bar2.html"); + result.Message.Text.ShouldBe("Message Bar 2."); + result.Level.ShouldBe(FailureLevel.Warning); + result.Kind.ShouldBe(ResultKind.Fail); + + result.Locations.Count.ShouldBe(1); + physicalLocation = result.Locations[0].PhysicalLocation; + physicalLocation.ArtifactLocation.Uri.OriginalString.ShouldBe("src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs"); + physicalLocation.Region.StartLine.ShouldBe(23); + physicalLocation.Region.EndLine.ShouldBe(42); + physicalLocation.Region.StartColumn.ShouldBe(5); + physicalLocation.Region.EndColumn.ShouldBe(10); + + run.OriginalUriBaseIds.Count.ShouldBe(1); + run.OriginalUriBaseIds[SarifIssueReportGenerator.RepoRootUriBaseId].Uri.LocalPath.ShouldBe(SarifIssueReportFixture.RepositoryRootPath); + } + } + } +} diff --git a/src/Cake.Issues.Reporting.Sarif/Cake.Issues.Reporting.Sarif.csproj b/src/Cake.Issues.Reporting.Sarif/Cake.Issues.Reporting.Sarif.csproj new file mode 100644 index 000000000..08bfe292b --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif/Cake.Issues.Reporting.Sarif.csproj @@ -0,0 +1,48 @@ + + + + Library + net6.0;net7.0;net8.0 + Support for creating SARIF compatible files for the Cake.Issues addin for Cake Build Automation System + Cake Issues contributors + Copyright © Cake Issues contributors + Cake.Issues + + + + full + true + AllEnabledByDefault + ..\Cake.Issues.ruleset + true + + + + bin\Debug\Cake.Issues.Reporting.Sarif.xml + DEBUG;TRACE + + + + bin\Release\Cake.Issues.Reporting.Sarif.xml + TRACE + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Sarif/IIssueExtensions.cs b/src/Cake.Issues.Reporting.Sarif/IIssueExtensions.cs new file mode 100644 index 000000000..f12474140 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif/IIssueExtensions.cs @@ -0,0 +1,113 @@ +namespace Cake.Issues.Reporting.Sarif +{ + using System; + using Cake.Core.IO; + using Microsoft.CodeAnalysis.Sarif; + + /// + /// Extensions for . + /// + internal static class IIssueExtensions + { + /// + /// Returns the kind of the issue. + /// + /// Issue for which the kind should be returned. + /// Kind of the issue. + public static ResultKind Kind(this IIssue issue) + { + issue.NotNull(nameof(issue)); + + if (!issue.Priority.HasValue) + { + return ResultKind.None; + } + + return issue.Priority switch + { + (int)IssuePriority.Suggestion or (int)IssuePriority.Hint => ResultKind.Informational, + (int)IssuePriority.Warning or (int)IssuePriority.Error => ResultKind.Fail, + _ => ResultKind.NotApplicable, + }; + } + + /// + /// Returns the level of the issue. + /// + /// Issue for which the level should be returned. + /// Level of the issue. + public static FailureLevel Level(this IIssue issue) + { + issue.NotNull(nameof(issue)); + + if (!issue.Priority.HasValue) + { + return FailureLevel.None; + } + + return issue.Priority switch + { + (int)IssuePriority.Suggestion or (int)IssuePriority.Hint => FailureLevel.Note, + (int)IssuePriority.Warning => FailureLevel.Warning, + (int)IssuePriority.Error => FailureLevel.Error, + _ => FailureLevel.None, + }; + } + + /// + /// Returns the location of the issue. + /// + /// Issue for which the location should be returned. + /// Location of the issue. + public static Location Location(this IIssue issue) + { + issue.NotNull(nameof(issue)); + + if (issue.AffectedFileRelativePath == null && !issue.Line.HasValue) + { + return null; + } + + var result = new Location + { + PhysicalLocation = new PhysicalLocation(), + }; + + if (issue.AffectedFileRelativePath != null) + { + result.PhysicalLocation.ArtifactLocation = + new ArtifactLocation + { + UriBaseId = SarifIssueReportGenerator.RepoRootUriBaseId, + Uri = new Uri(issue.FilePath(), UriKind.RelativeOrAbsolute), + }; + } + + if (issue.Line.HasValue) + { + result.PhysicalLocation.Region = + new Region + { + StartLine = issue.Line.Value, + }; + + if (issue.EndLine.HasValue) + { + result.PhysicalLocation.Region.EndLine = issue.EndLine.Value; + } + + if (issue.Column.HasValue) + { + result.PhysicalLocation.Region.StartColumn = issue.Column.Value; + } + + if (issue.EndColumn.HasValue) + { + result.PhysicalLocation.Region.EndColumn = issue.EndColumn.Value; + } + } + + return result; + } + } +} diff --git a/src/Cake.Issues.Reporting.Sarif/Properties/ProjectInfo.cs b/src/Cake.Issues.Reporting.Sarif/Properties/ProjectInfo.cs new file mode 100644 index 000000000..7b6227983 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif/Properties/ProjectInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2b32529d-dd2b-458d-ae6f-81cec5b06d0b")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.Reporting.Sarif.Tests")] diff --git a/src/Cake.Issues.Reporting.Sarif/SarifIssueReportFormatAliases.cs b/src/Cake.Issues.Reporting.Sarif/SarifIssueReportFormatAliases.cs new file mode 100644 index 000000000..99f3ce3c4 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif/SarifIssueReportFormatAliases.cs @@ -0,0 +1,76 @@ +namespace Cake.Issues.Reporting.Sarif +{ + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Issues.Reporting; + + /// + /// Contains functionality to generate SARIF compatible files. + /// + /// NOTE: Use Cake.Issues.Reporting.Sarif addin to use these aliases with Cake Script Runners and + /// Cake.Frosting.Issues.Reporting.Sarif to use these aliases with Cake Frosting. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class SarifIssueReportFormatAliases + { + /// + /// Gets an instance of the SARIF report format using default settings. + /// + /// The context. + /// Instance of a SARIF report format. + /// + /// Create SARIF compatible file: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat SarifIssueReportFormat( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return context.SarifIssueReportFormat(new SarifIssueReportFormatSettings()); + } + + /// + /// Gets an instance of the SARIF report format using specified settings. + /// + /// The context. + /// Settings for generating the report. + /// Instance of a SARIF report format. + /// + /// Create SARIF compatible file: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(ReportingAliasConstants.ReportingFormatCakeAliasCategory)] + public static IIssueReportFormat SarifIssueReportFormat( + this ICakeContext context, + SarifIssueReportFormatSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new SarifIssueReportGenerator(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.Reporting.Sarif/SarifIssueReportFormatSettings.cs b/src/Cake.Issues.Reporting.Sarif/SarifIssueReportFormatSettings.cs new file mode 100644 index 000000000..cb910cb2e --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif/SarifIssueReportFormatSettings.cs @@ -0,0 +1,9 @@ +namespace Cake.Issues.Reporting.Sarif +{ + /// + /// Settings for . + /// + public class SarifIssueReportFormatSettings + { + } +} diff --git a/src/Cake.Issues.Reporting.Sarif/SarifIssueReportGenerator.cs b/src/Cake.Issues.Reporting.Sarif/SarifIssueReportGenerator.cs new file mode 100644 index 000000000..89e3f9d82 --- /dev/null +++ b/src/Cake.Issues.Reporting.Sarif/SarifIssueReportGenerator.cs @@ -0,0 +1,166 @@ +namespace Cake.Issues.Reporting.Sarif +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Microsoft.CodeAnalysis.Sarif; + using Newtonsoft.Json; + + /// + /// Generator for creating SARIF compatible reports. + /// + internal class SarifIssueReportGenerator : IssueReportFormat + { + /// + /// The symbolic name for the repository root location, used in UriBaseIds. + /// + internal const string RepoRootUriBaseId = "REPOROOT"; + + /// + /// The name of the result object property bag property that holds the rule URL in the + /// unusual case where the ruleId is absent but the URL is present. + /// + internal const string RuleUrlPropertyName = "RuleUrl"; + + private readonly SarifIssueReportFormatSettings sarifIssueReportFormatSettings; + private List rules; + private Dictionary ruleIndices; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake log context. + /// Settings for reading the log file. + public SarifIssueReportGenerator(ICakeLog log, SarifIssueReportFormatSettings settings) + : base(log) + { + settings.NotNull(nameof(settings)); + + this.sarifIssueReportFormatSettings = settings; + } + + /// + protected override FilePath InternalCreateReport(IEnumerable issues) + { + this.Log.Information("Creating report '{0}'", this.Settings.OutputFilePath.FullPath); + + var settings = new JsonSerializerSettings() + { + Formatting = Formatting.Indented, + }; + + var log = new SarifLog(); + + if (issues.Any()) + { + log.Runs = new List(); + foreach (var issueGroup in from issue in issues group issue by new { issue.ProviderType, issue.Run }) + { + this.rules = []; + this.ruleIndices = []; + + Run run = new() + { + Tool = + new Tool + { + Driver = + new ToolComponent + { + Name = issueGroup.Key.ProviderType, + }, + }, + Results = + (from issue in issueGroup + select this.GetResult(issue)).ToList(), + OriginalUriBaseIds = new Dictionary + { + [RepoRootUriBaseId] = + new ArtifactLocation + { + Uri = new Uri(this.Settings.RepositoryRoot.FullPath, UriKind.Absolute), + }, + }, + }; + + if (!string.IsNullOrEmpty(issueGroup.Key.Run)) + { + run.AutomationDetails = + new RunAutomationDetails + { + Id = issueGroup.Key.Run, + }; + } + + if (this.rules.Count != 0) + { + run.Tool.Driver.Rules = this.rules; + } + + log.Runs.Add(run); + } + } + + var sarifText = JsonConvert.SerializeObject(log, settings); + File.WriteAllText(this.Settings.OutputFilePath.FullPath, sarifText); + + return this.Settings.OutputFilePath; + } + + private Result GetResult(IIssue issue) + { + issue.NotNull(nameof(issue)); + + var result = + new Result + { + RuleId = issue.RuleId, + Message = + new Message + { + Text = issue.MessageText, + Markdown = issue.MessageMarkdown, + }, + Kind = issue.Kind(), + Level = issue.Level(), + Locations = + new List + { + issue.Location(), + }, + }; + + if (issue.RuleUrl != null) + { + if (!string.IsNullOrEmpty(issue.RuleId)) + { + if (!this.ruleIndices.TryGetValue(issue.RuleId, out int value)) + { + this.ruleIndices.Add(issue.RuleId, this.rules.Count); + this.rules.Add( + new ReportingDescriptor + { + Id = issue.RuleId, + Name = issue.RuleName, + HelpUri = issue.RuleUrl, + }); + } + + result.RuleIndex = value; + } + else + { + // In the unusual case where there is a rule URL but no rule name, we put the + // URL in the result's property bag, because there's no rule whose metadata + // can hold it. + result.SetProperty(RuleUrlPropertyName, issue.RuleUrl); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Reporting.Tests/Cake.Issues.Reporting.Tests.csproj b/src/Cake.Issues.Reporting.Tests/Cake.Issues.Reporting.Tests.csproj index edd050d08..2478db0f3 100644 --- a/src/Cake.Issues.Reporting.Tests/Cake.Issues.Reporting.Tests.csproj +++ b/src/Cake.Issues.Reporting.Tests/Cake.Issues.Reporting.Tests.csproj @@ -21,8 +21,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive
    - - + + diff --git a/src/Cake.Issues.Reporting/IssueReportFormat.cs b/src/Cake.Issues.Reporting/IssueReportFormat.cs index ccf441d69..67d88eb4f 100644 --- a/src/Cake.Issues.Reporting/IssueReportFormat.cs +++ b/src/Cake.Issues.Reporting/IssueReportFormat.cs @@ -7,17 +7,10 @@ /// /// Base class for all report format implementations. /// - public abstract class IssueReportFormat : BaseIssueComponent, IIssueReportFormat + /// The Cake log context. + public abstract class IssueReportFormat(ICakeLog log) + : BaseIssueComponent(log), IIssueReportFormat { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - protected IssueReportFormat(ICakeLog log) - : base(log) - { - } - /// public FilePath CreateReport(IEnumerable issues) { diff --git a/src/Cake.Issues.Sarif.Tests/Cake.Issues.Sarif.Tests.csproj b/src/Cake.Issues.Sarif.Tests/Cake.Issues.Sarif.Tests.csproj new file mode 100644 index 000000000..b5fb5dfc5 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Cake.Issues.Sarif.Tests.csproj @@ -0,0 +1,54 @@ + + + + Library + net6.0 + Tests for the Cake.Issues.Sarif addin + Cake Issues contributors + Cake.Issues + Copyright © Cake Issues contributors + + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + + + + + + + 4.0.0 + + + 4.2.1 + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + 2.7.1 + + + 2.5.8 + runtime; build; native; contentfiles; analyzers + all + + + + + + + + + + diff --git a/src/Cake.Issues.Sarif.Tests/Properties/ProjectInfo.cs b/src/Cake.Issues.Sarif.Tests/Properties/ProjectInfo.cs new file mode 100644 index 000000000..c77f8c50f --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Properties/ProjectInfo.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7f97c3e5-25d7-4fb2-9b8b-6ae39e8acbe8")] diff --git a/src/Cake.Issues.Sarif.Tests/SarifIssuesProviderFixture.cs b/src/Cake.Issues.Sarif.Tests/SarifIssuesProviderFixture.cs new file mode 100644 index 000000000..27c04f6f0 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/SarifIssuesProviderFixture.cs @@ -0,0 +1,10 @@ +namespace Cake.Issues.Sarif.Tests +{ + using Cake.Issues.Testing; + + internal class SarifIssuesProviderFixture(string fileResourceName) + : BaseConfigurableIssueProviderFixture(fileResourceName) + { + protected override string FileResourceNamespace => "Cake.Issues.Sarif.Tests.Testfiles."; + } +} diff --git a/src/Cake.Issues.Sarif.Tests/SarifIssuesProviderTests.cs b/src/Cake.Issues.Sarif.Tests/SarifIssuesProviderTests.cs new file mode 100644 index 000000000..0918d3a76 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/SarifIssuesProviderTests.cs @@ -0,0 +1,178 @@ +namespace Cake.Issues.Sarif.Tests +{ + using System; + using System.Linq; + using Cake.Issues.Testing; + using Cake.Testing; + using Shouldly; + using Xunit; + + public sealed class SarifIssuesProviderTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => + new SarifIssuesProvider( + null, + new SarifIssuesSettings("Foo".ToByteArray()))); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_IssueProviderSettings_Are_Null() + { + // Given / When + var result = Record.Exception(() => new SarifIssuesProvider(new FakeLog(), null)); + + // Then + result.IsArgumentNullException("issueProviderSettings"); + } + } + + public sealed class TheReadIssuesMethod + { + [Fact] + public void Should_Read_Issue_Correct_For_Minimal_File() + { + // Given + var fixture = new SarifIssuesProviderFixture("minimal.sarif"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(0); + } + + [Fact] + public void Should_Read_Issue_Correct_For_Recomended_File_Without_Source() + { + // Given + var fixture = new SarifIssuesProviderFixture("recommended-without-source.sarif"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + var issue = issues.Single(); + IssueChecker.Check( + issue, + IssueBuilder.NewIssue( + "The insecure method \"Crypto.Sha1.Encrypt\" should not be used.", + "Cake.Issues.Sarif.SarifIssuesProvider", + "BinaryScanner") + .OfRule("B6412") + .WithPriority(IssuePriority.Warning) + .Create()); + } + + [Fact] + public void Should_Read_Issue_Correct_For_Recomended_File_With_Source() + { + // Given + var fixture = new SarifIssuesProviderFixture("recommended-with-source.sarif"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + var issue = issues.Single(); + IssueChecker.Check( + issue, + IssueBuilder.NewIssue( + "Variable \"count\" was used without being initialized.", + "Cake.Issues.Sarif.SarifIssuesProvider", + "CodeScanner") + .InFile(@"src\collections\list.cpp", 15) + .OfRule("C2001") + .WithPriority(IssuePriority.Warning) + .Create()); + } + + [Fact] + public void Should_Read_Issue_Correct_For_Comprehensive_File() + { + // Given + var fixture = new SarifIssuesProviderFixture("comprehensive.sarif"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + var issue = issues.Single(); + IssueChecker.Check( + issue, + IssueBuilder.NewIssue( + "Variable \"ptr\" was used without being initialized." + Environment.NewLine + + " It was declared [here](0).", + "Cake.Issues.Sarif.SarifIssuesProvider", + "CodeScanner") + .WithMessageInMarkdownFormat( + "Variable `ptr` was used without being initialized." + Environment.NewLine + + " It was declared [here](0).") + .InFile(@"collections\list.h", 15) + .OfRule("C2001") + .WithPriority(IssuePriority.Error) + .Create()); + } + + [Fact] + public void Should_Read_Issue_Correct_For_File_Generated_By_CakeIssuesReportingSarif() + { + // Given + var fixture = new SarifIssuesProviderFixture("cake.issues.reporting.sarif.sarif"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(3); + + var issue = issues[0]; + IssueChecker.Check( + issue, + IssueBuilder.NewIssue( + "Message Foo.", + "Cake.Issues.Sarif.SarifIssuesProvider", + "ProviderType Foo") + .InFile(@"src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs", 10) + .OfRule("Rule Foo") + .WithPriority(IssuePriority.Error) + .Create()); + + issue = issues[1]; + IssueChecker.Check( + issue, + IssueBuilder.NewIssue( + "Message Bar.", + "Cake.Issues.Sarif.SarifIssuesProvider", + "ProviderType Bar") + .WithMessageInMarkdownFormat("Message Bar -- now in **Markdown**!") + .InFile(@"src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs", 12) + .OfRule("Rule Bar", new Uri("https://www.example.come/rules/bar.html")) + .WithPriority(IssuePriority.Warning) + .Create()); + + issue = issues[2]; + IssueChecker.Check( + issue, + IssueBuilder.NewIssue( + "Message Bar 2.", + "Cake.Issues.Sarif.SarifIssuesProvider", + "ProviderType Bar") + .InFile(@"src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs", 42) + .WithPriority(IssuePriority.Warning) + .Create()); + } + } + } +} diff --git a/src/Cake.Issues.Sarif.Tests/SarifIssuesSettingsTests.cs b/src/Cake.Issues.Sarif.Tests/SarifIssuesSettingsTests.cs new file mode 100644 index 000000000..f5926df20 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/SarifIssuesSettingsTests.cs @@ -0,0 +1,80 @@ +namespace Cake.Issues.Sarif.Tests +{ + using System; + using Cake.Core.IO; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class SarifIssuesSettingsTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_LogFilePath_Is_Null() + { + // Given + FilePath logFilePath = null; + + // When + var result = Record.Exception(() => new SarifIssuesSettings(logFilePath)); + + // Then + result.IsArgumentNullException("logFilePath"); + } + + [Fact] + public void Should_Throw_If_LogFileContent_Is_Null() + { + // Given + byte[] logFileContent = null; + + // When + var result = Record.Exception(() => new SarifIssuesSettings(logFileContent)); + + // Then + result.IsArgumentNullException("logFileContent"); + } + + [Fact] + public void Should_Set_LogFileContent() + { + // Given + var logFileContent = "Foo".ToByteArray(); + + // When + var settings = new SarifIssuesSettings(logFileContent); + + // Then + settings.LogFileContent.ShouldBe(logFileContent); + } + + [Fact] + public void Should_Set_LogFileContent_If_Empty() + { + // Given + byte[] logFileContent = []; + + // When + var settings = new SarifIssuesSettings(logFileContent); + + // Then + settings.LogFileContent.ShouldBe(logFileContent); + } + + [Fact] + public void Should_Set_LogFileContent_From_LogFilePath() + { + // Given + using (var tempFile = new ResourceTempFile("Cake.Issues.Sarif.Tests.Testfiles.minimal.sarif")) + { + // When + var settings = new SarifIssuesSettings(tempFile.FileName); + + // Then + settings.LogFileContent.ShouldBe(tempFile.Content); + } + } + } + } +} diff --git a/src/Cake.Issues.Sarif.Tests/Testfiles/cake.issues.reporting.sarif.sarif b/src/Cake.Issues.Sarif.Tests/Testfiles/cake.issues.reporting.sarif.sarif new file mode 100644 index 000000000..8eb52766f --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Testfiles/cake.issues.reporting.sarif.sarif @@ -0,0 +1,104 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "ProviderType Foo" + } + }, + "originalUriBaseIds": { + "REPOROOT": { + "uri": "file:///c:/Source/Cake.Issues.Reporting.Sarif" + } + }, + "results": [ + { + "ruleId": "Rule Foo", + "level": "error", + "message": { + "text": "Message Foo." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs", + "uriBaseId": "REPOROOT" + }, + "region": { + "startLine": 10 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + }, + { + "tool": { + "driver": { + "name": "ProviderType Bar", + "rules": [ + { + "id": "Rule Bar", + "helpUri": "https://www.example.come/rules/bar.html" + } + ] + } + }, + "originalUriBaseIds": { + "REPOROOT": { + "uri": "file:///c:/Source/Cake.Issues.Reporting.Sarif" + } + }, + "results": [ + { + "ruleId": "Rule Bar", + "ruleIndex": 0, + "message": { + "text": "Message Bar.", + "markdown": "Message Bar -- now in **Markdown**!" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs", + "uriBaseId": "REPOROOT" + }, + "region": { + "startLine": 12 + } + } + } + ] + }, + { + "message": { + "text": "Message Bar 2." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs", + "uriBaseId": "REPOROOT" + }, + "region": { + "startLine": 42 + } + } + } + ], + "properties": { + "RuleUrl": "https://www.example.come/rules/bar2.html" + } + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Sarif.Tests/Testfiles/comprehensive.sarif b/src/Cake.Issues.Sarif.Tests/Testfiles/comprehensive.sarif new file mode 100644 index 000000000..73e131d24 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Testfiles/comprehensive.sarif @@ -0,0 +1,758 @@ +{ + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "automationId": { + "guid": "BC650830-A9FE-44CB-8818-AD6C387279A0", + "id": "Nightly code scan/2018-10-08" + }, + "baselineGuid": "0A106451-C9B1-4309-A7EE-06988B95F723", + "runAggregates": [ + { + "id": "Build/14.0.1.2/Release/20160716-13:22:18", + "correlationGuid": "26F138B6-6014-4D3D-B174-6E1ACE9439F3" + } + ], + "tool": { + "driver": { + "name": "CodeScanner", + "fullName": "CodeScanner 1.1 for Microsoft Windows (R) (en-US)", + "version": "2.1", + "semanticVersion": "2.1.0", + "dottedQuadFileVersion": "2.1.0.0", + "releaseDateUtc": "2019-03-17", + "organization": "Example Corporation", + "product": "Code Scanner", + "productSuite": "Code Quality Tools", + "shortDescription": { + "text": "A scanner for code." + }, + "fullDescription": { + "text": "A really great scanner for all your code." + }, + "properties": { + "copyright": "Copyright (c) 2017 by Example Corporation." + }, + "globalMessageStrings": { + "variableDeclared": { + "text": "Variable \"{0}\" was declared here.", + "markdown": " Variable `{0}` was declared here." + } + }, + "rules": [ + { + "id": "C2001", + "deprecatedIds": [ + "CA2000" + ], + "defaultConfiguration": { + "level": "error", + "rank": 95 + }, + "shortDescription": { + "text": "A variable was used without being initialized." + }, + "fullDescription": { + "text": "A variable was used without being initialized. This can result + + in runtime errors such as null reference exceptions." + }, + "messageStrings": { + "default": { + "text": "Variable \"{0}\" was used without being initialized. + It was declared [here]({1}).", + "markdown": "Variable `{0}` was used without being initialized. + It was declared [here]({1})." + } + } + } + ], + "notifications": [ + { + "id": "start", + "shortDescription": { + "text": "The run started." + }, + "messageStrings": { + "default": { + "text": "Run started." + } + } + }, + { + "id": "end", + "shortDescription": { + "text": "The run ended." + }, + "messageStrings": { + "default": { + "text": "Run ended." + } + } + } + ], + "language": "en-US" + }, + "extensions": [ + { + "name": "CodeScanner Security Rules", + "version": "3.1", + "rules": [ + { + "id": "S0001", + "defaultConfiguration": { + "level": "error" + }, + "shortDescription": { + "text": "Do not use weak cryptographic algorithms." + }, + "messageStrings": { + "default": { + "text": "The cryptographic algorithm '{0}' should not be used." + } + } + } + ] + } + ] + }, + "language": "en-US", + "versionControlProvenance": [ + { + "repositoryUri": "https://github.com/example-corp/browser", + "revisionId": "5da53fbb2a0aaa12d648b73984acc9aac2e11c2a", + "mappedTo": { + "uriBaseId": "PROJECTROOT" + } + } + ], + "originalUriBaseIds": { + "PROJECTROOT": { + "uri": "file://build.example.com/work/" + }, + "SRCROOT": { + "uri": " src/", + "uriBaseId": "PROJECTROOT" + }, + "BINROOT": { + "uri": " bin/", + "uriBaseId": "PROJECTROOT" + } + }, + "invocations": [ + { + "commandLine": "CodeScanner @build/collections.rsp", + "responseFiles": [ + { + "uri": "build/collections.rsp", + "uriBaseId": "SRCROOT", + "index": 0 + } + ], + "startTimeUtc": "2016-07-16T14:18:25Z", + "endTimeUtc": "2016-07-16T14:19:01Z", + "machine": "BLD01", + "account": "buildAgent", + "processId": 1218, + "fileName": "/bin/tools/CodeScanner", + "workingDirectory": { + "uri": "file:///home/buildAgent/src" + }, + "environmentVariables": { + "PATH": "/usr/local/bin:/bin:/bin/tools:/home/buildAgent/bin", + "HOME": "/home/buildAgent", + "TZ": "EST" + }, + "toolConfigurationNotifications": [ + { + "descriptor": { + "id": "UnknownRule" + }, + "associatedRule": { + "ruleId": "ABC0001" + }, + "level": "warning", + "message": { + "text": "Could not disable rule \"ABC0001\" because + + there is no rule with that id." + } + } + ], + "toolExecutionNotifications": [ + { + "descriptor": { + "id": "CTN0001" + }, + "level": "note", + "message": { + "text": "Run started." + } + }, + { + "descriptor": { + "id": "CTN9999" + }, + "associatedRule": { + "id": "C2001", + "index": 0, + }, + "level": "error", + "message": { + "text": "Exception evaluating rule \"C2001\". Rule disabled; + + run continues." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "crypto/hash.cpp", + "uriBaseId": "SRCROOT", + "index": 4 + } + } + } + ], + "threadId": 52, + "timeUtc": "2016-07-16T14:18:43.119Z", + "exception": { + "kind": "ExecutionEngine.RuleFailureException", + "message": "Unhandled exception during rule evaluation.", + "stack": { + "frames": [ + { + "location": { + "message": { + "text": "Exception thrown" + }, + "logicalLocations": [ + { + "fullyQualifiedName": "Rules.SecureHashAlgorithmRule.Evaluate" + } + ], + "physicalLocation": { + "address": { + "offset": 4244988 + } + } + }, + "module": "RuleLibrary", + "threadId": 52 + }, + { + "location": { + "logicalLocations": [ + { + "fullyQualifiedName": "ExecutionEngine.Engine.EvaluateRule" + } + ], + "physicalLocation": { + "address": { + "offset": 4245514 + } + } + }, + "module": "ExecutionEngine", + "threadId": 52 + } + ] + }, + "innerExceptions": [ + { + "kind": "System.ArgumentException", + "message": "length is < 0" + } + ] + } + }, + { + "descriptor": { + "id": "CTN0002" + }, + "level": "note", + "message": { + "text": "Run ended." + } + } + ], + "exitCode": 0, + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "build/collections.rsp", + "uriBaseId": "SRCROOT" + }, + "mimeType": "text/plain", + "length": 81, + "contents": { + "text": "-input src/collections/*.cpp -log out/collections.sarif -rules all -disable C9999" + } + }, + { + "location": { + "uri": "application/main.cpp", + "uriBaseId": "SRCROOT" + }, + "sourceLanguage": "cplusplus", + "length": 1742, + "hashes": { + "sha-256": "cc8e6a99f3eff00adc649fee132ba80fe333ea5a" + } + }, + { + "location": { + "uri": "collections/list.cpp", + "uriBaseId": "SRCROOT" + }, + "sourceLanguage": "cplusplus", + "length": 980, + "hashes": { + "sha-256": "b13ce2678a8807ba0765ab94a0ecd394f869bc81" + } + }, + { + "location": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT" + }, + "sourceLanguage": "cplusplus", + "length": 24656, + "hashes": { + "sha-256": "849be119aaba4e9f88921a99e3036fb6c2a8144a" + } + }, + { + "location": { + "uri": "crypto/hash.cpp", + "uriBaseId": "SRCROOT" + }, + "sourceLanguage": "cplusplus", + "length": 1424, + "hashes": { + "sha-256": "3ffe2b77dz255cdf95f97d986d7a6ad8f287eaed" + } + }, + { + "location": { + "uri": "app.zip", + "uriBaseId": "BINROOT" + }, + "mimeType": "application/zip", + "length": 310450, + "hashes": { + "sha-256": "df18a5e74b6b46ddaa23ad7271ee2b7c5731cbe1" + } + }, + { + "location": { + "uri": "/docs/intro.docx" + }, + "mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "parentIndex": 5, + "offset": 17522, + "length": 4050 + } + ], + "logicalLocations": [ + { + "name": "add", + "fullyQualifiedName": "collections::list::add", + "decoratedName": "?add@list@collections@@QAEXH@Z", + "kind": "function", + "parentIndex": 1 + }, + { + "name": "list", + "fullyQualifiedName": "collections::list", + "kind": "type", + "parentIndex": 2 + }, + { + "name": "collections", + "kind": "namespace" + }, + { + "name": "add_core", + "fullyQualfiedName": "collections::list::add_core", + "decoratedName": "?add_core@list@collections@@QAEXH@Z", + "kind": "function", + "parentIndex": 1 + }, + { + "fullyQualifiedName": "main", + "kind": "function" + } + ], + "results": [ + { + "ruleId": "C2001", + "ruleIndex": 0, + "kind": "fail", + "level": "error", + "message": { + "id": "default", + "arguments": [ + "ptr", + "0" + ] + }, + "suppressions": [ + { + "kind": "external", + "state": "accepted" + } + ], + "baselineState": "unchanged", + "rank": 95, + "analysisTarget": { + "uri": "collections/list.cpp", + "uriBaseId": "SRCROOT", + "index": 2 + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 15, + "startColumn": 9, + "endLine": 15, + "endColumn": 10, + "charLength": 1, + "charOffset": 254, + "snippet": { + "text": "add_core(ptr, offset, val);\n return;" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add", + "index": 0 + } + ] + } + ], + "relatedLocations": [ + { + "id": 0, + "message": { + "id": "variableDeclared", + "arguments": [ + "ptr" + ] + }, + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 8, + "startColumn": 5 + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add", + "index": 0 + } + ] + } + ], + "codeFlows": [ + { + "message": { + "text": "Path from declaration to usage" + }, + "threadFlows": [ + { + "id": "thread-52", + "locations": [ + { + "importance": "essential", + "location": { + "message": { + "text": "Variable \"ptr\" declared.", + "markdown": "Variable `ptr` declared." + }, + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 15, + "snippet": { + "text": "int *ptr;" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add", + "index": 0 + } + ] + }, + "module": "platform" + }, + { + "state": { + "y": { + "text": "2" + }, + "z": { + "text": "4" + }, + "y + z": { + "text": "6" + }, + "q": { + "text": "7" + } + }, + "importance": "unimportant", + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 15, + "snippet": { + "text": "offset = (y + z) * q + 1;" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add", + "index": 0 + } + ], + "annotations": [ + { + "startLine": 15, + "startColumn": 13, + "endColumn": 19, + "message": { + "text": "(y + z) = 42", + "markdown": "`(y + z) = 42`" + } + } + ], + }, + "module": "platform" + }, + { + "importance": "essential", + "location": { + "message": { + "text": "Uninitialized variable \"ptr\" passed to + + method \"add_core\".", + "markdown": "Uninitialized variable `ptr` passed to + + method `add_core`." + }, + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 25, + "snippet": { + "text": "add_core(ptr, offset, val)" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add", + "index": 0 + } + ] + }, + "module": "platform" + } + ] + } + ] + } + ], + "stacks": [ + { + "message": { + "text": "Call stack resulting from usage of uninitialized variable." + }, + "frames": [ + { + "location": { + "message": { + "text": "Exception thrown." + }, + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 110, + "startColumn": 15 + }, + "address": { + "offset": 4229178 + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add_core", + "index": 0 + } + ], + }, + "module": "platform", + "threadId": 52, + "parameters": [ + "null", + "0", + "14" + ] + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "region": { + "startLine": 43, + "startColumn": 15 + }, + "address": { + "offset": 4229268 + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add", + "index": 0 + } + ] + }, + "module": "platform", + "threadId": 52, + "parameters": [ + "14" + ] + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "application/main.cpp", + "uriBaseId": "SRCROOT", + "index": 1 + }, + "region": { + "startLine": 28, + "startColumn": 9 + }, + "address": { + "offset": 4229836 + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "main", + "index": 4 + } + ] + }, + "module": "application", + "threadId": 52 + } + ] + } + ], + "addresses": [ + { + "baseAddress": 4194304, + "fullyQualifiedName": "collections.dll", + "kind": "module", + "section": ".text" + }, + { + "offset": 100, + "fullyQualifiedName": "collections.dll!collections::list::add", + "kind": "function", + "parentIndex": 0 + }, + { + "offset": 22, + "fullyQualifiedName": "collections.dll!collections::list::add+0x16", + "parentIndex": 1 + } + ], + "fixes": [ + { + "description": { + "text": "Initialize the variable to null" + }, + "artifactChanges": [ + { + "artifactLocation": { + "uri": "collections/list.h", + "uriBaseId": "SRCROOT", + "index": 3 + }, + "replacements": [ + { + "deletedRegion": { + "startLine": 42 + }, + "insertedContent": { + "text": "A different line\n" + } + } + ] + } + ] + } + ], + "hostedViewerUri": "https://www.example.com/viewer/3918d370-c636-40d8-bf23-8c176043a2df", + "workItemUris": [ + "https://github.com/example/project/issues/42", + "https://github.com/example/project/issues/54" + ], + "provenance": { + "firstDetectionTimeUtc": "2016-07-15T14:20:42Z", + "firstDetectionRunGuid": "8F62D8A0-C14F-4516-9959-1A663BA6FB99", + "lastDetectionTimeUtc": "2016-07-16T14:20:42Z", + "lastDetectionRunGuid": "BC650830-A9FE-44CB-8818-AD6C387279A0", + "invocationIndex": 0 + } + } + ] + } + ] + } \ No newline at end of file diff --git a/src/Cake.Issues.Sarif.Tests/Testfiles/minimal.sarif b/src/Cake.Issues.Sarif.Tests/Testfiles/minimal.sarif new file mode 100644 index 000000000..b716920d8 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Testfiles/minimal.sarif @@ -0,0 +1,13 @@ +{ + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "CodeScanner" + } + }, + "results": [] + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Sarif.Tests/Testfiles/recommended-with-source.sarif b/src/Cake.Issues.Sarif.Tests/Testfiles/recommended-with-source.sarif new file mode 100644 index 000000000..762923948 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Testfiles/recommended-with-source.sarif @@ -0,0 +1,67 @@ +{ + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "CodeScanner", + "rules": [ + { + "id": "C2001", + "fullDescription": { + "text": "A variable was used without being initialized. This can result + + in runtime errors such as null reference exceptions." + }, + "messageStrings": { + "default": { + "text": "Variable \"{0}\" was used without being initialized." + } + } + } + ] + } + }, + "artifacts": [ + { + "location": { + "uri": "src/collections/list.cpp", + "uriBaseId": "SRCROOT" + }, + "sourceLanguage": "c" + } + ], + "results": [ + { + "ruleId": "C2001", + "ruleIndex": 0, + "message": { + "id": "default", + "arguments": [ + "count" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/collections/list.cpp", + "uriBaseId": "SRCROOT", + "index": 0 + }, + "region": { + "startLine": 15 + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "collections::list::add" + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Sarif.Tests/Testfiles/recommended-without-source.sarif b/src/Cake.Issues.Sarif.Tests/Testfiles/recommended-without-source.sarif new file mode 100644 index 000000000..ef7e0a260 --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Testfiles/recommended-without-source.sarif @@ -0,0 +1,57 @@ +{ + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "BinaryScanner" + } + }, + "artifact": [ + { + "location": { + "uri": "bin/example", + "uriBaseId": "BINROOT" + } + } + ], + "logicalLocations": [ + { + "name": "Example", + "kind": "namespace" + }, + { + "name": "Worker", + "fullyQualifiedName": "Example.Worker", + "kind": "type", + "parentIndex": 0 + }, + { + "name": "DoWork", + "fullyQualifiedName": "Example.Worker.DoWork", + "kind": "function", + "parentIndex": 1 + } + ], + "results": [ + { + "ruleId": "B6412", + "message": { + "text": "The insecure method \"Crypto.Sha1.Encrypt\" should not be used." + }, + "level": "warning", + "locations": [ + { + "logicalLocations": [ + { + "fullyQualifiedName": "Example.Worker.DoWork", + "index": 2 + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Sarif.Tests/Testfiles/rule-metadata-1.json b/src/Cake.Issues.Sarif.Tests/Testfiles/rule-metadata-1.json new file mode 100644 index 000000000..49fb94dbc --- /dev/null +++ b/src/Cake.Issues.Sarif.Tests/Testfiles/rule-metadata-1.json @@ -0,0 +1,27 @@ +{ + "version": "1.0.0", + "runs": [ + { + "tool": { + "name": "BinaryAnalyzer", + "semanticVersion": "2.1.0" + }, + "rules": { + "BA2006": { + "id": "BA2006", + "name": "BuildWithSecureTools", + "shortDescription": "Application code should be compiled with the most up-to-date tool sets.", + "fullDescription": "Application code should be compiled with the most up-to-date tool sets. The latest version is 2.2.", + "messageFormats": { + "Error_BadModule": "built with {0} compiler version {1} (Front end version {2})", + "Pass": "{0} was built with tools that satisfy configured policy.", + "Error": "{0} was compiled with one or tools that do not satisfy configured policy.", + "NotApplicable_InvalidMetadata": "{0} was not evaluated for check '{1}'." + }, + "defaultLevel": "warning", + "helpUri": "http://www.example.com/tools/BinaryAnalyzer/rules/BA2006" + } + } + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Sarif/Cake.Issues.Sarif.csproj b/src/Cake.Issues.Sarif/Cake.Issues.Sarif.csproj new file mode 100644 index 000000000..1841afbe4 --- /dev/null +++ b/src/Cake.Issues.Sarif/Cake.Issues.Sarif.csproj @@ -0,0 +1,49 @@ + + + + + net6.0;net7.0;net8.0 + Support for SARIF compatible files for the Cake.Issues Addin for Cake Build Automation System + Cake Issues contributors + Cake.Issues + Copyright © Cake Issues contributors + + + + latest + full + ..\Cake.Issues.ruleset + AllEnabledByDefault + true + + + + bin\Debug\Cake.Issues.Sarif.xml + DEBUG;TRACE + + + + bin\Release\Cake.Issues.Sarif.xml + TRACE + + + + + 4.0.0 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + + + + diff --git a/src/Cake.Issues.Sarif/FailureLevelExtensions.cs b/src/Cake.Issues.Sarif/FailureLevelExtensions.cs new file mode 100644 index 000000000..19dae42f3 --- /dev/null +++ b/src/Cake.Issues.Sarif/FailureLevelExtensions.cs @@ -0,0 +1,27 @@ +namespace Cake.Issues.Sarif +{ + using Microsoft.CodeAnalysis.Sarif; + + /// + /// Extension methods for the enumeration. + /// + internal static class FailureLevelExtensions + { + /// + /// Returns the priority of the issue. + /// + /// Level of the sarif result. + /// Priority of the issue. + public static IssuePriority ToPriority(this FailureLevel level) + { + return level switch + { + FailureLevel.None => IssuePriority.Undefined, + FailureLevel.Note => IssuePriority.Suggestion, + FailureLevel.Warning => IssuePriority.Warning, + FailureLevel.Error => IssuePriority.Error, + _ => IssuePriority.Undefined, + }; + } + } +} diff --git a/src/Cake.Issues.Sarif/Properties/ProjectInfo.cs b/src/Cake.Issues.Sarif/Properties/ProjectInfo.cs new file mode 100644 index 000000000..3ba7720a5 --- /dev/null +++ b/src/Cake.Issues.Sarif/Properties/ProjectInfo.cs @@ -0,0 +1,14 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("89c40d93-bb4c-4ccb-a4de-f046fd2b7d64")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.Sarif.Tests")] \ No newline at end of file diff --git a/src/Cake.Issues.Sarif/SarifIssuesAliases.cs b/src/Cake.Issues.Sarif/SarifIssuesAliases.cs new file mode 100644 index 000000000..5b5429685 --- /dev/null +++ b/src/Cake.Issues.Sarif/SarifIssuesAliases.cs @@ -0,0 +1,120 @@ +namespace Cake.Issues.Sarif +{ + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Core.IO; + + /// + /// Contains functionality for reading issues from SARIF files. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class SarifIssuesAliases + { + /// + /// Gets the name of the SARIF issue provider. + /// This name can be used to identify issues based on the property. + /// + /// The context. + /// Name of the SARIF issue provider. + [CakePropertyAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static string SarifIssuesProviderTypeName( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return typeof(SarifIssuesProvider).FullName; + } + + /// + /// Gets an instance of a provider for SARIF compatible files using a file from disk. + /// + /// The context. + /// Path to the SARIF file. + /// Instance of a provider for SARIF compatible files. + /// + /// Read issues from a SARIF compatible file: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider SarifIssuesFromFilePath( + this ICakeContext context, + FilePath logFilePath) + { + context.NotNull(nameof(context)); + logFilePath.NotNull(nameof(logFilePath)); + + return context.SarifIssues(new SarifIssuesSettings(logFilePath)); + } + + /// + /// Gets an instance of a provider for SARIF compatible files using file content. + /// + /// The context. + /// Content of the SARIF compatible file. + /// Instance of a provider for SARIF compatible files. + /// + /// Read issues from a SARIF compatible file: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider SarifIssuesFromContent( + this ICakeContext context, + string logFileContent) + { + context.NotNull(nameof(context)); + logFileContent.NotNullOrWhiteSpace(nameof(logFileContent)); + + return context.SarifIssues(new SarifIssuesSettings(logFileContent.ToByteArray())); + } + + /// + /// Gets an instance of a provider for SARIF compatible files using specified settings. + /// + /// The context. + /// Settings for reading the SARIF compatible file. + /// Instance of a provider for SARIF compatible files. + /// + /// Read issues from a SARIF compatible file: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider SarifIssues( + this ICakeContext context, + SarifIssuesSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new SarifIssuesProvider(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.Sarif/SarifIssuesProvider.cs b/src/Cake.Issues.Sarif/SarifIssuesProvider.cs new file mode 100644 index 000000000..3aecd3b8e --- /dev/null +++ b/src/Cake.Issues.Sarif/SarifIssuesProvider.cs @@ -0,0 +1,183 @@ +namespace Cake.Issues.Sarif +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Cake.Core.Diagnostics; + using Cake.Issues; + using Microsoft.CodeAnalysis.Sarif; + using Newtonsoft.Json; + + /// + /// Provider for issues in SARIF compatible formt. + /// + /// The Cake log context. + /// Settings for the issue provider. + internal class SarifIssuesProvider(ICakeLog log, SarifIssuesSettings issueProviderSettings) : BaseConfigurableIssueProvider(log, issueProviderSettings) + { + /// + public override string ProviderName => "SARIF"; + + /// + protected override IEnumerable InternalReadIssues() + { + var result = new List(); + + var logContent = + JsonConvert.DeserializeObject(this.IssueProviderSettings.LogFileContent.ToStringUsingEncoding()); + + foreach (var run in logContent.Runs) + { + var toolName = run.Tool.Driver.Name; + + foreach (var sarifResult in run.Results) + { + var (text, markdown) = GetMessage(sarifResult, run); + var (ruleId, ruleUrl) = GetRule(sarifResult, run); + var (filePath, line) = GetLocation(sarifResult); + + // Build issue. + var issueBuilder = + IssueBuilder + .NewIssue( + text, + typeof(SarifIssuesProvider).FullName, + toolName) + .WithPriority(sarifResult.Level.ToPriority()) + .OfRule(ruleId, ruleUrl); + + if (!string.IsNullOrEmpty(markdown)) + { + issueBuilder = + issueBuilder + .WithMessageInMarkdownFormat(markdown); + } + + if (filePath != null) + { + issueBuilder = + issueBuilder + .InFile(filePath, line); + } + + result.Add(issueBuilder.Create()); + } + } + + return result; + } + + /// + /// Determines the message for a SARIF result. + /// + /// Result to read the message from. + /// SARIF run description. + /// Message of the result. + private static (string Text, string Markdown) GetMessage( + Result result, + Run run) + { + // Once https://github.com/microsoft/sarif-sdk/issues/430 is implemented this code should become mostly obsolete + result.NotNull(nameof(result)); + run.NotNull(nameof(run)); + + // If result has message text assigned directly. + if (!string.IsNullOrEmpty(result.Message.Text)) + { + return (result.Message.Text, result.Message.Markdown); + } + + // If result has global message or message defined on rule. + if (!string.IsNullOrEmpty(result.Message.Id)) + { + // Check if a message defined on the rule was referenced. + var rule = result.GetRule(run); + if (rule.MessageStrings.TryGetValue(result.Message.Id, out var ruleMessage)) + { + var arguments = result.Message.Arguments; + return GetFormattedMessage(ruleMessage, arguments); + } + + // Check if a global message was referenced. + if (run.Tool.Driver.GlobalMessageStrings.TryGetValue(result.Message.Id, out var globalMessage)) + { + var arguments = result.Message.Arguments; + return GetFormattedMessage(globalMessage, arguments); + } + } + + return (null, null); + + static (string Text, string Markdown) GetFormattedMessage( + MultiformatMessageString message, + IList arguments) + { + if (arguments.Any()) + { + string messageText = null; + string messageMarkdown = null; + + if (!string.IsNullOrEmpty(message.Text)) + { + messageText = string.Format(message.Text, arguments.ToArray()); + } + + if (!string.IsNullOrEmpty(message.Markdown)) + { + messageMarkdown = string.Format(message.Markdown, arguments.ToArray()); + } + + return (messageText, messageMarkdown); + } + + return (message.Text, message.Markdown); + } + } + + /// + /// Determines the rule for a SARIF result. + /// + /// Result to read the rule from. + /// SARIF run description. + /// File and line of the result. + private static (string RuleId, Uri RuleUrl) GetRule( + Result result, + Run run) + { + result.NotNull(nameof(result)); + run.NotNull(nameof(run)); + + var rule = result.GetRule(run); + + return (rule.Id, rule.HelpUri); + } + + /// + /// Determines the location for a SARIF result. + /// + /// Result to read the location from. + /// File and line of the result. + private static (string FilePath, int? Line) GetLocation( + Result result) + { + result.NotNull(nameof(result)); + + // Only consider the first location. + var location = result.Locations.FirstOrDefault(); + if (location != null && location.PhysicalLocation != null) + { + var filePath = location.PhysicalLocation.ArtifactLocation.Uri.ToString(); + + int? line = null; + if (location.PhysicalLocation.Region != null) + { + line = location.PhysicalLocation.Region.StartLine; + } + + return (filePath, line); + } + + return (null, null); + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Sarif/SarifIssuesSettings.cs b/src/Cake.Issues.Sarif/SarifIssuesSettings.cs new file mode 100644 index 000000000..7c2f332f1 --- /dev/null +++ b/src/Cake.Issues.Sarif/SarifIssuesSettings.cs @@ -0,0 +1,28 @@ +namespace Cake.Issues.Sarif +{ + using Cake.Core.IO; + + /// + /// Settings for . + /// + public class SarifIssuesSettings : IssueProviderSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Path to the Sarif file. + public SarifIssuesSettings(FilePath logFilePath) + : base(logFilePath) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Content of the SARIF file. + public SarifIssuesSettings(byte[] logFileContent) + : base(logFileContent) + { + } + } +} diff --git a/src/Cake.Issues.Terraform.Tests/Cake.Issues.Terraform.Tests.csproj b/src/Cake.Issues.Terraform.Tests/Cake.Issues.Terraform.Tests.csproj new file mode 100644 index 000000000..a1a305f71 --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/Cake.Issues.Terraform.Tests.csproj @@ -0,0 +1,57 @@ + + + + Library + net6.0 + false + Tests for the Cake.Issues.Terraform addin + Cake Issues contributors + Cake.Issues + Copyright © Cake Issues contributors + + + ..\Cake.Issues.Tests.ruleset + + + ..\Cake.Issues.Tests.ruleset + + + + + + + + + + + + + + 4.0.0 + + + 4.2.1 + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + 2.7.1 + + + 2.5.8 + runtime; build; native; contentfiles; analyzers + all + + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Terraform.Tests/Properties/ProjectInfo.cs b/src/Cake.Issues.Terraform.Tests/Properties/ProjectInfo.cs new file mode 100644 index 000000000..51a16e4a3 --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/Properties/ProjectInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3c1e1ff5-c57e-4e46-85a9-ba3dde8b00b5")] diff --git a/src/Cake.Issues.Terraform.Tests/TerraformProviderFixture.cs b/src/Cake.Issues.Terraform.Tests/TerraformProviderFixture.cs new file mode 100644 index 000000000..dfd0a0fee --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/TerraformProviderFixture.cs @@ -0,0 +1,30 @@ +namespace Cake.Issues.Terraform.Tests +{ + using System.Collections.Generic; + using Cake.Core.IO; + using Cake.Issues.Testing; + + internal class TerraformProviderFixture : BaseConfigurableIssueProviderFixture + { + private readonly DirectoryPath docRootPath; + + public TerraformProviderFixture(string fileResourceName, DirectoryPath docRootPath) + : base(fileResourceName) + { + docRootPath.NotNull(nameof(docRootPath)); + + this.docRootPath = docRootPath; + this.ReadIssuesSettings = + new ReadIssuesSettings(@"c:\Source\Cake.Issues"); + } + + protected override string FileResourceNamespace => "Cake.Issues.Terraform.Tests.Testfiles."; + + protected override IList GetCreateIssueProviderSettingsArguments() + { + var result = base.GetCreateIssueProviderSettingsArguments(); + result.Add(this.docRootPath); + return result; + } + } +} diff --git a/src/Cake.Issues.Terraform.Tests/TerraformProviderTests.cs b/src/Cake.Issues.Terraform.Tests/TerraformProviderTests.cs new file mode 100644 index 000000000..88b395075 --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/TerraformProviderTests.cs @@ -0,0 +1,100 @@ +namespace Cake.Issues.Terraform.Tests +{ + using System.Linq; + using System.Runtime.InteropServices; + using Cake.Issues.Testing; + using Cake.Testing; + using Shouldly; + using Xunit; + + public sealed class TerraformProviderTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => + new TerraformIssuesProvider( + null, + new TerraformIssuesSettings("Foo".ToByteArray(), @"c:\Source\Cake.Issues"))); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_IssueProviderSettings_Are_Null() + { + var result = Record.Exception(() => + new TerraformIssuesProvider( + new FakeLog(), + null)); + + // Then + result.IsArgumentNullException("issueProviderSettings"); + } + } + + // Test cases based on https://github.com/hashicorp/terraform-json/blob/master/validate_test.go + public sealed class TheReadIssuesMethod + { + [SkippableFact] + public void Should_Read_Basic_Issues_Correct() + { + // Uses Windows specific paths. + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + + // Given + var fixture = new TerraformProviderFixture("basic.json", @"./"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(2); + IssueChecker.Check( + issues[0], + IssueBuilder.NewIssue( + "\"anonymous\": [DEPRECATED] For versions later than 3.0.0, absence of a token enables this mode", + "Cake.Issues.Terraform.TerraformIssuesProvider", + "Terraform") + .WithPriority(IssuePriority.Warning)); + IssueChecker.Check( + issues[1], + IssueBuilder.NewIssue( + "The argument \"name\" is required, but no definition was found.", + "Cake.Issues.Terraform.TerraformIssuesProvider", + "Terraform") + .InFile("main.tf", 14, 14, 37, 37) + .OfRule("Missing required argument") + .WithPriority(IssuePriority.Error)); + } + + [SkippableFact] + public void Should_Read_Error_Correct() + { + // Uses Windows specific paths. + Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + + // Given + var fixture = new TerraformProviderFixture("error.json", @"./"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + IssueChecker.Check( + issues[0], + IssueBuilder.NewIssue( + "\nPlugin reinitialization required...", + "Cake.Issues.Terraform.TerraformIssuesProvider", + "Terraform") + .OfRule("Could not load plugin") + .WithPriority(IssuePriority.Error)); + } + } + } +} diff --git a/src/Cake.Issues.Terraform.Tests/TerraformSettingsTests.cs b/src/Cake.Issues.Terraform.Tests/TerraformSettingsTests.cs new file mode 100644 index 000000000..6cc09503f --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/TerraformSettingsTests.cs @@ -0,0 +1,147 @@ +namespace Cake.Issues.Terraform.Tests +{ + using System; + using Cake.Core.IO; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class TerraformSettingsTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_ValidateOutputFilePath_Is_Null() + { + // Given + FilePath validateOutputFilePath = null; + var terraformRootPath = @"c:\Source\Cake.Issues\docs"; + + // When + var result = Record.Exception(() => + new TerraformIssuesSettings(validateOutputFilePath, terraformRootPath)); + + // Then + result.IsArgumentNullException("logFilePath"); + } + + [Fact] + public void Should_Throw_If_TerraformRootPath_For_ValidateOutputFilePath_Is_Null() + { + // Given + DirectoryPath terraformRootPath = null; + + using (var tempFile = new ResourceTempFile("Cake.Issues.Terraform.Tests.Testfiles.basic.json")) + { + // When + var result = Record.Exception(() => + new TerraformIssuesSettings(tempFile.FileName, terraformRootPath)); + + // Then + result.IsArgumentNullException("terraformRootPath"); + } + } + + [Fact] + public void Should_Throw_If_ValidateOutput_Is_Null() + { + // Given + byte[] validateOutput = null; + var terraformRootPath = @"c:\Source\Cake.Issues\docs"; + + // When + var result = Record.Exception(() => new TerraformIssuesSettings(validateOutput, terraformRootPath)); + + // Then + result.IsArgumentNullException("logFileContent"); + } + + [Fact] + public void Should_Throw_If_TerraformRootPath_For_ValidateOutput_Is_Null() + { + // Given + var validateOutput = "foo".ToByteArray(); + DirectoryPath terraformRootPath = null; + + // When + var result = Record.Exception(() => + new TerraformIssuesSettings(validateOutput, terraformRootPath)); + + // Then + result.IsArgumentNullException("terraformRootPath"); + } + + [Fact] + public void Should_Set_ValidateOutput() + { + // Given + var validateOutput = "Foo".ToByteArray(); + var terraformRootPath = @"c:\Source\Cake.Issues\docs"; + + // When + var settings = new TerraformIssuesSettings(validateOutput, terraformRootPath); + + // Then + settings.LogFileContent.ShouldBe(validateOutput); + } + + [Fact] + public void Should_Set_ValidateOutput_If_Empty() + { + // Given + byte[] validateOutput = Array.Empty(); + var terraformRootPath = @"c:\Source\Cake.Issues\docs"; + + // When + var settings = new TerraformIssuesSettings(validateOutput, terraformRootPath); + + // Then + settings.LogFileContent.ShouldBe(validateOutput); + } + + [Fact] + public void Should_Set_TerraformRootPath() + { + // Given + var validateOutput = "Foo".ToByteArray(); + var terraformRootPath = @"c:/Source/Cake.Issues/docs"; + + // When + var settings = new TerraformIssuesSettings(validateOutput, terraformRootPath); + + // Then + settings.TerraformRootPath.ToString().ShouldBe(terraformRootPath); + } + + [Fact] + public void Should_Set_ValidateOutput_From_ValidateOutputFilePath() + { + // Given + var terraformRootPath = @"c:\Source\Cake.Issues\docs"; + using (var tempFile = new ResourceTempFile("Cake.Issues.Terraform.Tests.Testfiles.basic.json")) + { + // When + var settings = new TerraformIssuesSettings(tempFile.FileName, terraformRootPath); + + // Then + settings.LogFileContent.ShouldBe(tempFile.Content); + } + } + + [Fact] + public void Should_Set_TerraformRootPath_From_ValidateOutputFilePath() + { + // Given + var terraformRootPath = @"c:/Source/Cake.Issues/docs"; + using (var tempFile = new ResourceTempFile("Cake.Issues.Terraform.Tests.Testfiles.basic.json")) + { + // When + var settings = new TerraformIssuesSettings(tempFile.FileName, terraformRootPath); + + // Then + settings.TerraformRootPath.ToString().ShouldBe(terraformRootPath); + } + } + } + } +} diff --git a/src/Cake.Issues.Terraform.Tests/Testfiles/basic.json b/src/Cake.Issues.Terraform.Tests/Testfiles/basic.json new file mode 100644 index 000000000..d52ebcf1a --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/Testfiles/basic.json @@ -0,0 +1,29 @@ +{ + "valid": false, + "error_count": 1, + "warning_count": 1, + "diagnostics": [ + { + "severity": "warning", + "summary": "\"anonymous\": [DEPRECATED] For versions later than 3.0.0, absence of a token enables this mode" + }, + { + "severity": "error", + "summary": "Missing required argument", + "detail": "The argument \"name\" is required, but no definition was found.", + "range": { + "filename": "main.tf", + "start": { + "line": 14, + "column": 37, + "byte": 200 + }, + "end": { + "line": 14, + "column": 37, + "byte": 200 + } + } + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Terraform.Tests/Testfiles/error.json b/src/Cake.Issues.Terraform.Tests/Testfiles/error.json new file mode 100644 index 000000000..10b1d4eba --- /dev/null +++ b/src/Cake.Issues.Terraform.Tests/Testfiles/error.json @@ -0,0 +1,12 @@ +{ + "valid": false, + "error_count": 1, + "warning_count": 0, + "diagnostics": [ + { + "severity": "error", + "summary": "Could not load plugin", + "detail": "\nPlugin reinitialization required..." + } + ] +} \ No newline at end of file diff --git a/src/Cake.Issues.Terraform/Cake.Issues.Terraform.csproj b/src/Cake.Issues.Terraform/Cake.Issues.Terraform.csproj new file mode 100644 index 000000000..3b6e63f0f --- /dev/null +++ b/src/Cake.Issues.Terraform/Cake.Issues.Terraform.csproj @@ -0,0 +1,43 @@ + + + + Library + net6.0;net7.0;net8.0 + Terraform support for the Cake.Issues Addin for Cake Build Automation System + Cake Issues contributors + Cake.Issues + Copyright © Cake Issues contributors + + + bin\Debug\Cake.Issues.Terraform.xml + ..\Cake.Issues.ruleset + DEBUG;TRACE + + + bin\Release\Cake.Issues.Terraform.xml + ..\Cake.Issues.ruleset + TRACE + + + full + AllEnabledByDefault + + + + 4.0.0 + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + 1.2.0-beta.556 + runtime; build; native; contentfiles; analyzers + all + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.Terraform/Properties/ProjectInfo.cs b/src/Cake.Issues.Terraform/Properties/ProjectInfo.cs new file mode 100644 index 000000000..67e8715ea --- /dev/null +++ b/src/Cake.Issues.Terraform/Properties/ProjectInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0d5b570e-dfca-4fcb-8528-c7b96ee0f5d3")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.Terraform.Tests")] \ No newline at end of file diff --git a/src/Cake.Issues.Terraform/TerraformIssuesAliases.cs b/src/Cake.Issues.Terraform/TerraformIssuesAliases.cs new file mode 100644 index 000000000..f24a8fe34 --- /dev/null +++ b/src/Cake.Issues.Terraform/TerraformIssuesAliases.cs @@ -0,0 +1,191 @@ +namespace Cake.Issues.Terraform +{ + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Core.IO; + + /// + /// Contains functionality related to reading output from terraform validate -json. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class TerraformIssuesAliases + { + /// + /// Gets the name of the Terraform issue provider. + /// This name can be used to identify issues based on the property. + /// + /// The context. + /// Name of the Terraform issue provider. + [CakePropertyAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static string TerraformIssuesProviderTypeName( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return TerraformIssuesProvider.ProviderTypeName; + } + + /// + /// Gets an instance of a provider for reading output from terraform validate -json from disk + /// for Terraform scripts in the repository root. + /// + /// The context. + /// Path to the output of the terraform validate command. + /// Instance of a provider for warnings reported by terraform validate. + /// + /// Read warnings reported by terraform validate: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider TerraformIssuesFromFilePath( + this ICakeContext context, + FilePath validateOutputFilePath) + { + context.NotNull(nameof(context)); + validateOutputFilePath.NotNull(nameof(validateOutputFilePath)); + + return context.TerraformIssuesFromFilePath(validateOutputFilePath, "/"); + } + + /// + /// Gets an instance of a provider for reading output from terraform validate -json from disk. + /// + /// The context. + /// Path to the output of the terraform validate command. + /// Path to the directory of the Terraform scripts. + /// Either the full path or the path relative to the repository root. + /// Instance of a provider for warnings reported by terraform validate. + /// + /// Read warnings reported by terraform validate: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider TerraformIssuesFromFilePath( + this ICakeContext context, + FilePath validateOutputFilePath, + DirectoryPath terraformRootPath) + { + context.NotNull(nameof(context)); + validateOutputFilePath.NotNull(nameof(validateOutputFilePath)); + terraformRootPath.NotNull(nameof(terraformRootPath)); + + return context.TerraformIssues(new TerraformIssuesSettings(validateOutputFilePath, terraformRootPath)); + } + + /// + /// Gets an instance of a provider for reading output from terraform validate -json + /// for Terraform scripts in the repository root. + /// + /// The context. + /// Content of the terraform validate command. + /// Instance of a provider for warnings reported by terraform validate. + /// + /// Read warnings reported by terraform validate: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider TerraformIssuesFromContent( + this ICakeContext context, + string validateOutput) + { + context.NotNull(nameof(context)); + validateOutput.NotNullOrWhiteSpace(nameof(validateOutput)); + + return context.TerraformIssues(new TerraformIssuesSettings(validateOutput.ToByteArray(), "/")); + } + + /// + /// Gets an instance of a provider for reading output from terraform validate -json. + /// + /// The context. + /// Content of the terraform validate command. + /// Path to the directory of the Terraform scripts. + /// Either the full path or the path relative to the repository root. + /// Instance of a provider for warnings reported by terraform validate. + /// + /// Read warnings reported by terraform validate: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider TerraformIssuesFromContent( + this ICakeContext context, + string validateOutput, + DirectoryPath terraformRootPath) + { + context.NotNull(nameof(context)); + validateOutput.NotNullOrWhiteSpace(nameof(validateOutput)); + terraformRootPath.NotNull(nameof(terraformRootPath)); + + return context.TerraformIssues(new TerraformIssuesSettings(validateOutput.ToByteArray(), terraformRootPath)); + } + + /// + /// Gets an instance of a provider for reading output from terraform validate -json using specified settings. + /// + /// The context. + /// Settings for reading the issues. + /// Instance of a provider for warnings reported by terraform validate. + /// + /// Read warnings reported by terraform validate: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider TerraformIssues( + this ICakeContext context, + TerraformIssuesSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new TerraformIssuesProvider(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.Terraform/TerraformIssuesProvider.cs b/src/Cake.Issues.Terraform/TerraformIssuesProvider.cs new file mode 100644 index 000000000..ee421ee7f --- /dev/null +++ b/src/Cake.Issues.Terraform/TerraformIssuesProvider.cs @@ -0,0 +1,137 @@ +namespace Cake.Issues.Terraform +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Runtime.Serialization.Json; + using System.Text; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + + /// + /// Provider for warnings reported by Terraform. + /// + /// The Cake log context. + /// Settings for the issue provider. + internal class TerraformIssuesProvider(ICakeLog log, TerraformIssuesSettings issueProviderSettings) + : BaseConfigurableIssueProvider(log, issueProviderSettings) + { + /// + /// Gets the name of the Terraform issue provider. + /// This name can be used to identify issues based on the property. + /// + public static string ProviderTypeName => typeof(TerraformIssuesProvider).FullName; + + /// + public override string ProviderName => "Terraform"; + + /// + protected override IEnumerable InternalReadIssues() + { + // Determine path of the doc root. + var terraformRootPath = this.IssueProviderSettings.TerraformRootPath; + if (terraformRootPath.IsRelative) + { + terraformRootPath = terraformRootPath.MakeAbsolute(this.Settings.RepositoryRoot); + } + + ValidateFile validateFile = null; + + var logFileContent = this.IssueProviderSettings.LogFileContent.ToStringUsingEncoding(true); + + using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(logFileContent))) + { + var jsonSerializer = new DataContractJsonSerializer(typeof(ValidateFile)); + validateFile = jsonSerializer.ReadObject(ms) as ValidateFile; + } + + return + from diagnostic in validateFile.diagnostics + select + IssueBuilder + .NewIssue(GetMessage(diagnostic.summary, diagnostic.detail), this) + .InFile( + this.TryGetFile(diagnostic.range?.filename, terraformRootPath), + diagnostic.range?.start?.line, + diagnostic.range?.end?.line, + diagnostic.range?.start?.column, + diagnostic.range?.end?.column) + .OfRule(GetRule(diagnostic.summary, diagnostic.detail)) + .WithPriority(GetPriority(diagnostic.severity)) + .Create(); + } + + /// + /// Returns the message for an issue based on summary and detail. + /// + /// Summary of the diagnostic entry. + /// Detail of the diagnostic entry. + /// Issue message. + private static string GetMessage(string summary, string detail) + { + // If a diagnostic entry only contains a summary we use it for message instead of rule. + if (string.IsNullOrWhiteSpace(detail)) + { + return summary; + } + + return detail; + } + + /// + /// Returns the rule for an issue based on summary and detail. + /// + /// Summary of the diagnostic entry. + /// Detail of the diagnostic entry. + /// Issue message. + private static string GetRule(string summary, string detail) + { + // If a diagnostic entry only contains a summary we don't use it for rule as it is already used for message. + if (string.IsNullOrWhiteSpace(detail)) + { + return null; + } + + return summary; + } + + /// + /// Converts the severity to a priority. + /// + /// Severity as reported by Terraform. + /// Priority. + private static IssuePriority GetPriority(string severity) + { + return severity.ToLowerInvariant() switch + { + "error" => IssuePriority.Error, + "warning" => IssuePriority.Warning, + _ => IssuePriority.Undefined, + }; + } + + /// + /// Reads the affected file path from a issue logged by terraform validate. + /// + /// The file name in the current log entry. + /// Absolute path to the root directory of the Terraform scripts. + /// The full path to the affected file. + private string TryGetFile( + string fileName, + DirectoryPath terraformRootPath) + { + if (string.IsNullOrWhiteSpace(fileName)) + { + return null; + } + + // Add path to repository root + fileName = terraformRootPath.CombineWithFilePath(fileName).FullPath; + + // Make path relative to repository root. + return + fileName + .MakeFilePathRelativeToRepositoryRoot(this.Settings); + } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.Terraform/TerraformIssuesSettings.cs b/src/Cake.Issues.Terraform/TerraformIssuesSettings.cs new file mode 100644 index 000000000..219897bf1 --- /dev/null +++ b/src/Cake.Issues.Terraform/TerraformIssuesSettings.cs @@ -0,0 +1,44 @@ +namespace Cake.Issues.Terraform +{ + using Cake.Core.IO; + + /// + /// Settings for . + /// + public class TerraformIssuesSettings : IssueProviderSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Path to the the Terraform output file. + /// Path to the directory of the Terraform scripts. + /// Either the full path or the path relative to the repository root. + public TerraformIssuesSettings(FilePath validateOutputFilePath, DirectoryPath terraformRootPath) + : base(validateOutputFilePath) + { + terraformRootPath.NotNull(nameof(terraformRootPath)); + + this.TerraformRootPath = terraformRootPath; + } + + /// + /// Initializes a new instance of the class. + /// + /// Output of the Terraform validate command. + /// Path to the directory of the Terraform scripts. + /// Either the full path or the path relative to the repository root. + public TerraformIssuesSettings(byte[] validateOutput, DirectoryPath terraformRootPath) + : base(validateOutput) + { + terraformRootPath.NotNull(nameof(terraformRootPath)); + + this.TerraformRootPath = terraformRootPath; + } + + /// + /// Gets the path to the directory of the Terraform scripts. + /// Either the full path or the path relative to the repository root. + /// + public DirectoryPath TerraformRootPath { get; private set; } + } +} diff --git a/src/Cake.Issues.Terraform/ValidateOutputDataContract.cs b/src/Cake.Issues.Terraform/ValidateOutputDataContract.cs new file mode 100644 index 000000000..c7b87635d --- /dev/null +++ b/src/Cake.Issues.Terraform/ValidateOutputDataContract.cs @@ -0,0 +1,73 @@ +namespace Cake.Issues.Terraform +{ + using System.Runtime.Serialization; + +#pragma warning disable SA1310 // Field names must not contain underscore +#pragma warning disable SA1401 // Fields must be private +#pragma warning disable SA1307 // Accessible fields must begin with upper-case letter +#pragma warning disable SA1402 // File may only contain a single class +#pragma warning disable SA1600 // Elements must be documented +#pragma warning disable SA1649 // File name must match first type name + + [DataContract] + internal class ValidateFile + { + [DataMember] + public bool valid; + + [DataMember] + public int error_count; + + [DataMember] + public int warning_count; + + [DataMember] + public Diagnostic[] diagnostics; + } + + [DataContract] + internal class Diagnostic + { + [DataMember] + public string severity; + + [DataMember] + public string summary; + + [DataMember] + public string detail; + + [DataMember] + public Range range; + } + + [DataContract] + internal class Range + { + [DataMember] + public string filename; + + [DataMember] + public Location start; + + [DataMember] + public Location end; + } + + [DataContract] + internal class Location + { + [DataMember] + public int line; + + [DataMember] + public int column; + } + +#pragma warning restore SA1310 // Field names must not contain underscore +#pragma warning restore SA1401 // Fields must be private +#pragma warning restore SA1307 // Accessible fields must begin with upper-case letter +#pragma warning restore SA1402 // File may only contain a single class +#pragma warning restore SA1600 // Elements must be documented +#pragma warning restore SA1649 // File name must match first type name +} \ No newline at end of file diff --git a/src/Cake.Issues.Testing/BaseMultiFormatIssueProviderFixture.cs b/src/Cake.Issues.Testing/BaseMultiFormatIssueProviderFixture.cs index 97441a4d5..3c6c63b92 100644 --- a/src/Cake.Issues.Testing/BaseMultiFormatIssueProviderFixture.cs +++ b/src/Cake.Issues.Testing/BaseMultiFormatIssueProviderFixture.cs @@ -9,20 +9,13 @@ /// Type of issue provider. /// Type of the settings for the issue provider. /// Type of the log file format. - public abstract class BaseMultiFormatIssueProviderFixture : BaseConfigurableIssueProviderFixture + /// Name of the resource to load. + public abstract class BaseMultiFormatIssueProviderFixture(string fileResourceName) + : BaseConfigurableIssueProviderFixture(fileResourceName) where TIssueProvider : BaseMultiFormatIssueProvider where TSettings : BaseMultiFormatIssueProviderSettings where TLogFileFormat : ILogFileFormat { - /// - /// Initializes a new instance of the class. - /// - /// Name of the resource to load. - protected BaseMultiFormatIssueProviderFixture(string fileResourceName) - : base(fileResourceName) - { - } - /// protected override IList GetCreateIssueProviderSettingsArguments() { diff --git a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj index 6369d9574..56f2b6349 100644 --- a/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj +++ b/src/Cake.Issues.Tests/Cake.Issues.Tests.csproj @@ -32,8 +32,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/Cake.Issues.sln b/src/Cake.Issues.sln index 2e97a5295..109f023be 100644 --- a/src/Cake.Issues.sln +++ b/src/Cake.Issues.sln @@ -102,6 +102,60 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Markdownlint", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Markdownlint.Tests", "Cake.Issues.Markdownlint.Tests\Cake.Issues.Markdownlint.Tests.csproj", "{B9306FB7-E104-4F71-8EF0-40A78E0919C0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AzureDevOps", "AzureDevOps", "{2502A3E6-F9F4-41A9-BCC5-BB815DC3F0FA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.PullRequests.AzureDevOps", "Cake.Issues.PullRequests.AzureDevOps\Cake.Issues.PullRequests.AzureDevOps.csproj", "{56FC9945-B0D4-4508-8DF8-C2E7A0EE3FC5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.PullRequests.AzureDevOps.Tests", "Cake.Issues.PullRequests.AzureDevOps.Tests\Cake.Issues.PullRequests.AzureDevOps.Tests.csproj", "{F417B206-8449-4FCA-A023-243B64C39A3B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Console", "Console", "{49FA3C0C-6261-41D0-9644-D6AFEDF89E6D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Reporting.Console", "Cake.Issues.Reporting.Console\Cake.Issues.Reporting.Console.csproj", "{A599D294-3B73-4BB4-8F77-F81389C0CE72}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Reporting.Console.Tests", "Cake.Issues.Reporting.Console.Tests\Cake.Issues.Reporting.Console.Tests.csproj", "{4BEC4558-8FA4-400C-9F3E-F1E6E086AF23}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Generic", "Generic", "{1FDAECA8-746E-4B18-BC89-D0876171CE58}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Reporting.Generic", "Cake.Issues.Reporting.Generic\Cake.Issues.Reporting.Generic.csproj", "{8EFC3069-854C-475B-9A27-8D5BA5B9124E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Reporting.Generic.Tests", "Cake.Issues.Reporting.Generic.Tests\Cake.Issues.Reporting.Generic.Tests.csproj", "{E0858010-710D-402E-B8E2-6CA41E503647}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitRepository", "GitRepository", "{106252E4-D531-4558-8A7D-77E9F60CC566}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.GitRepository", "Cake.Issues.GitRepository\Cake.Issues.GitRepository.csproj", "{0B870134-4F4A-4A55-A4C2-CBFBF9CCA67B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.GitRepository.Tests", "Cake.Issues.GitRepository.Tests\Cake.Issues.GitRepository.Tests.csproj", "{768546BE-125B-4D50-BFED-B8C4B60AF082}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppVeyor", "AppVeyor", "{1740ABB7-C3AE-437D-A7A5-0841BEEC3AF0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.PullRequests.AppVeyor", "Cake.Issues.PullRequests.AppVeyor\Cake.Issues.PullRequests.AppVeyor.csproj", "{41BA6C29-24C5-4BD6-9379-436850E00DCE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.PullRequests.AppVeyor.Tests", "Cake.Issues.PullRequests.AppVeyor.Tests\Cake.Issues.PullRequests.AppVeyor.Tests.csproj", "{2AB1CAC6-3F8A-4E00-8EEE-8C8682B453F4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sarif", "Sarif", "{43506DCC-B86E-418A-8626-F5C7E053B2D5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Reporting.Sarif", "Cake.Issues.Reporting.Sarif\Cake.Issues.Reporting.Sarif.csproj", "{C442C7D1-E3AA-4773-9994-45899CF00416}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Reporting.Sarif.Tests", "Cake.Issues.Reporting.Sarif.Tests\Cake.Issues.Reporting.Sarif.Tests.csproj", "{133DE375-8A58-4CA3-A727-0793B175D361}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sarif", "Sarif", "{308A600B-0745-464E-9487-9FCFB1BBAC7D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Sarif", "Cake.Issues.Sarif\Cake.Issues.Sarif.csproj", "{F2C036ED-DF46-4835-B9AF-C0E902867DE5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Sarif.Tests", "Cake.Issues.Sarif.Tests\Cake.Issues.Sarif.Tests.csproj", "{B4A35EB8-B671-440F-8620-87D998E40D34}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Terraform", "Terraform", "{9323409D-2A31-4D93-8479-3DBBC154816A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Terraform", "Cake.Issues.Terraform\Cake.Issues.Terraform.csproj", "{F9FC503D-6A0B-423F-BA00-9AAA7C9CAA17}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.Terraform.Tests", "Cake.Issues.Terraform.Tests\Cake.Issues.Terraform.Tests.csproj", "{5538D216-5A1B-4941-8E3E-B0BF32314751}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHubActions", "GitHubActions", "{E93E527B-60FF-45A3-BCAA-5AADA0A6DDB2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.PullRequests.GitHubActions", "Cake.Issues.PullRequests.GitHubActions\Cake.Issues.PullRequests.GitHubActions.csproj", "{D873FA70-A3EB-4B99-AD9B-D8879A752BD7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.Issues.PullRequests.GitHubActions.Tests", "Cake.Issues.PullRequests.GitHubActions.Tests\Cake.Issues.PullRequests.GitHubActions.Tests.csproj", "{7BFDC8EC-9CFB-4A15-8B00-41A922DD6019}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -176,6 +230,78 @@ Global {B9306FB7-E104-4F71-8EF0-40A78E0919C0}.Debug|Any CPU.Build.0 = Debug|Any CPU {B9306FB7-E104-4F71-8EF0-40A78E0919C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {B9306FB7-E104-4F71-8EF0-40A78E0919C0}.Release|Any CPU.Build.0 = Release|Any CPU + {56FC9945-B0D4-4508-8DF8-C2E7A0EE3FC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56FC9945-B0D4-4508-8DF8-C2E7A0EE3FC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56FC9945-B0D4-4508-8DF8-C2E7A0EE3FC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56FC9945-B0D4-4508-8DF8-C2E7A0EE3FC5}.Release|Any CPU.Build.0 = Release|Any CPU + {F417B206-8449-4FCA-A023-243B64C39A3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F417B206-8449-4FCA-A023-243B64C39A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F417B206-8449-4FCA-A023-243B64C39A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F417B206-8449-4FCA-A023-243B64C39A3B}.Release|Any CPU.Build.0 = Release|Any CPU + {A599D294-3B73-4BB4-8F77-F81389C0CE72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A599D294-3B73-4BB4-8F77-F81389C0CE72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A599D294-3B73-4BB4-8F77-F81389C0CE72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A599D294-3B73-4BB4-8F77-F81389C0CE72}.Release|Any CPU.Build.0 = Release|Any CPU + {4BEC4558-8FA4-400C-9F3E-F1E6E086AF23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BEC4558-8FA4-400C-9F3E-F1E6E086AF23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BEC4558-8FA4-400C-9F3E-F1E6E086AF23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BEC4558-8FA4-400C-9F3E-F1E6E086AF23}.Release|Any CPU.Build.0 = Release|Any CPU + {8EFC3069-854C-475B-9A27-8D5BA5B9124E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EFC3069-854C-475B-9A27-8D5BA5B9124E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EFC3069-854C-475B-9A27-8D5BA5B9124E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EFC3069-854C-475B-9A27-8D5BA5B9124E}.Release|Any CPU.Build.0 = Release|Any CPU + {E0858010-710D-402E-B8E2-6CA41E503647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0858010-710D-402E-B8E2-6CA41E503647}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0858010-710D-402E-B8E2-6CA41E503647}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0858010-710D-402E-B8E2-6CA41E503647}.Release|Any CPU.Build.0 = Release|Any CPU + {0B870134-4F4A-4A55-A4C2-CBFBF9CCA67B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B870134-4F4A-4A55-A4C2-CBFBF9CCA67B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B870134-4F4A-4A55-A4C2-CBFBF9CCA67B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B870134-4F4A-4A55-A4C2-CBFBF9CCA67B}.Release|Any CPU.Build.0 = Release|Any CPU + {768546BE-125B-4D50-BFED-B8C4B60AF082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {768546BE-125B-4D50-BFED-B8C4B60AF082}.Debug|Any CPU.Build.0 = Debug|Any CPU + {768546BE-125B-4D50-BFED-B8C4B60AF082}.Release|Any CPU.ActiveCfg = Release|Any CPU + {768546BE-125B-4D50-BFED-B8C4B60AF082}.Release|Any CPU.Build.0 = Release|Any CPU + {41BA6C29-24C5-4BD6-9379-436850E00DCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41BA6C29-24C5-4BD6-9379-436850E00DCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41BA6C29-24C5-4BD6-9379-436850E00DCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41BA6C29-24C5-4BD6-9379-436850E00DCE}.Release|Any CPU.Build.0 = Release|Any CPU + {2AB1CAC6-3F8A-4E00-8EEE-8C8682B453F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2AB1CAC6-3F8A-4E00-8EEE-8C8682B453F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AB1CAC6-3F8A-4E00-8EEE-8C8682B453F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2AB1CAC6-3F8A-4E00-8EEE-8C8682B453F4}.Release|Any CPU.Build.0 = Release|Any CPU + {C442C7D1-E3AA-4773-9994-45899CF00416}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C442C7D1-E3AA-4773-9994-45899CF00416}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C442C7D1-E3AA-4773-9994-45899CF00416}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C442C7D1-E3AA-4773-9994-45899CF00416}.Release|Any CPU.Build.0 = Release|Any CPU + {133DE375-8A58-4CA3-A727-0793B175D361}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {133DE375-8A58-4CA3-A727-0793B175D361}.Debug|Any CPU.Build.0 = Debug|Any CPU + {133DE375-8A58-4CA3-A727-0793B175D361}.Release|Any CPU.ActiveCfg = Release|Any CPU + {133DE375-8A58-4CA3-A727-0793B175D361}.Release|Any CPU.Build.0 = Release|Any CPU + {F2C036ED-DF46-4835-B9AF-C0E902867DE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2C036ED-DF46-4835-B9AF-C0E902867DE5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2C036ED-DF46-4835-B9AF-C0E902867DE5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2C036ED-DF46-4835-B9AF-C0E902867DE5}.Release|Any CPU.Build.0 = Release|Any CPU + {B4A35EB8-B671-440F-8620-87D998E40D34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4A35EB8-B671-440F-8620-87D998E40D34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4A35EB8-B671-440F-8620-87D998E40D34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4A35EB8-B671-440F-8620-87D998E40D34}.Release|Any CPU.Build.0 = Release|Any CPU + {F9FC503D-6A0B-423F-BA00-9AAA7C9CAA17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9FC503D-6A0B-423F-BA00-9AAA7C9CAA17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9FC503D-6A0B-423F-BA00-9AAA7C9CAA17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9FC503D-6A0B-423F-BA00-9AAA7C9CAA17}.Release|Any CPU.Build.0 = Release|Any CPU + {5538D216-5A1B-4941-8E3E-B0BF32314751}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5538D216-5A1B-4941-8E3E-B0BF32314751}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5538D216-5A1B-4941-8E3E-B0BF32314751}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5538D216-5A1B-4941-8E3E-B0BF32314751}.Release|Any CPU.Build.0 = Release|Any CPU + {D873FA70-A3EB-4B99-AD9B-D8879A752BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D873FA70-A3EB-4B99-AD9B-D8879A752BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D873FA70-A3EB-4B99-AD9B-D8879A752BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D873FA70-A3EB-4B99-AD9B-D8879A752BD7}.Release|Any CPU.Build.0 = Release|Any CPU + {7BFDC8EC-9CFB-4A15-8B00-41A922DD6019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BFDC8EC-9CFB-4A15-8B00-41A922DD6019}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BFDC8EC-9CFB-4A15-8B00-41A922DD6019}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BFDC8EC-9CFB-4A15-8B00-41A922DD6019}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -207,6 +333,33 @@ Global {3E907A2C-F70B-45F7-AF5A-6C55EDBDE4B7} = {D404813F-4EBD-4093-BA1C-B5BFEB781A65} {2EBB4FEA-1E52-4556-B228-E2F0D58C0055} = {3E907A2C-F70B-45F7-AF5A-6C55EDBDE4B7} {B9306FB7-E104-4F71-8EF0-40A78E0919C0} = {3E907A2C-F70B-45F7-AF5A-6C55EDBDE4B7} + {2502A3E6-F9F4-41A9-BCC5-BB815DC3F0FA} = {40421A26-BC87-4097-B9B5-EDA8229CB11E} + {56FC9945-B0D4-4508-8DF8-C2E7A0EE3FC5} = {2502A3E6-F9F4-41A9-BCC5-BB815DC3F0FA} + {F417B206-8449-4FCA-A023-243B64C39A3B} = {2502A3E6-F9F4-41A9-BCC5-BB815DC3F0FA} + {49FA3C0C-6261-41D0-9644-D6AFEDF89E6D} = {DDB9DE7A-2D15-4F19-9876-F93B7913DD5F} + {A599D294-3B73-4BB4-8F77-F81389C0CE72} = {49FA3C0C-6261-41D0-9644-D6AFEDF89E6D} + {4BEC4558-8FA4-400C-9F3E-F1E6E086AF23} = {49FA3C0C-6261-41D0-9644-D6AFEDF89E6D} + {1FDAECA8-746E-4B18-BC89-D0876171CE58} = {DDB9DE7A-2D15-4F19-9876-F93B7913DD5F} + {8EFC3069-854C-475B-9A27-8D5BA5B9124E} = {1FDAECA8-746E-4B18-BC89-D0876171CE58} + {E0858010-710D-402E-B8E2-6CA41E503647} = {1FDAECA8-746E-4B18-BC89-D0876171CE58} + {106252E4-D531-4558-8A7D-77E9F60CC566} = {D404813F-4EBD-4093-BA1C-B5BFEB781A65} + {0B870134-4F4A-4A55-A4C2-CBFBF9CCA67B} = {106252E4-D531-4558-8A7D-77E9F60CC566} + {768546BE-125B-4D50-BFED-B8C4B60AF082} = {106252E4-D531-4558-8A7D-77E9F60CC566} + {1740ABB7-C3AE-437D-A7A5-0841BEEC3AF0} = {40421A26-BC87-4097-B9B5-EDA8229CB11E} + {41BA6C29-24C5-4BD6-9379-436850E00DCE} = {1740ABB7-C3AE-437D-A7A5-0841BEEC3AF0} + {2AB1CAC6-3F8A-4E00-8EEE-8C8682B453F4} = {1740ABB7-C3AE-437D-A7A5-0841BEEC3AF0} + {43506DCC-B86E-418A-8626-F5C7E053B2D5} = {DDB9DE7A-2D15-4F19-9876-F93B7913DD5F} + {C442C7D1-E3AA-4773-9994-45899CF00416} = {43506DCC-B86E-418A-8626-F5C7E053B2D5} + {133DE375-8A58-4CA3-A727-0793B175D361} = {43506DCC-B86E-418A-8626-F5C7E053B2D5} + {308A600B-0745-464E-9487-9FCFB1BBAC7D} = {D404813F-4EBD-4093-BA1C-B5BFEB781A65} + {F2C036ED-DF46-4835-B9AF-C0E902867DE5} = {308A600B-0745-464E-9487-9FCFB1BBAC7D} + {B4A35EB8-B671-440F-8620-87D998E40D34} = {308A600B-0745-464E-9487-9FCFB1BBAC7D} + {9323409D-2A31-4D93-8479-3DBBC154816A} = {D404813F-4EBD-4093-BA1C-B5BFEB781A65} + {F9FC503D-6A0B-423F-BA00-9AAA7C9CAA17} = {9323409D-2A31-4D93-8479-3DBBC154816A} + {5538D216-5A1B-4941-8E3E-B0BF32314751} = {9323409D-2A31-4D93-8479-3DBBC154816A} + {E93E527B-60FF-45A3-BCAA-5AADA0A6DDB2} = {40421A26-BC87-4097-B9B5-EDA8229CB11E} + {D873FA70-A3EB-4B99-AD9B-D8879A752BD7} = {E93E527B-60FF-45A3-BCAA-5AADA0A6DDB2} + {7BFDC8EC-9CFB-4A15-8B00-41A922DD6019} = {E93E527B-60FF-45A3-BCAA-5AADA0A6DDB2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E9F2EC94-9A1B-4834-A464-E5208B210F11} diff --git a/src/Cake.Issues/BaseIssueProvider.cs b/src/Cake.Issues/BaseIssueProvider.cs index 2e9beecab..223b26545 100644 --- a/src/Cake.Issues/BaseIssueProvider.cs +++ b/src/Cake.Issues/BaseIssueProvider.cs @@ -6,17 +6,10 @@ /// /// Base class for all issue provider implementations. /// - public abstract class BaseIssueProvider : BaseIssueComponent, IIssueProvider + /// The Cake log context. + public abstract class BaseIssueProvider(ICakeLog log) + : BaseIssueComponent(log), IIssueProvider { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - protected BaseIssueProvider(ICakeLog log) - : base(log) - { - } - /// public abstract string ProviderName { get; } diff --git a/src/Cake.Issues/BaseMultiFormatIssueProvider.cs b/src/Cake.Issues/BaseMultiFormatIssueProvider.cs index 92ebb7042..457eb8629 100644 --- a/src/Cake.Issues/BaseMultiFormatIssueProvider.cs +++ b/src/Cake.Issues/BaseMultiFormatIssueProvider.cs @@ -8,20 +8,13 @@ /// /// Type of the settings. /// Type of the issue provider. - public abstract class BaseMultiFormatIssueProvider : BaseConfigurableIssueProvider + /// The Cake log context. + /// Settings for the issue provider. + public abstract class BaseMultiFormatIssueProvider(ICakeLog log, TSettings settings) + : BaseConfigurableIssueProvider(log, settings) where TSettings : BaseMultiFormatIssueProviderSettings where TIssueProvider : BaseMultiFormatIssueProvider { - /// - /// Initializes a new instance of the class. - /// - /// The Cake log context. - /// Settings for the issue provider. - protected BaseMultiFormatIssueProvider(ICakeLog log, TSettings settings) - : base(log, settings) - { - } - /// protected override IEnumerable InternalReadIssues() { diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 000000000..36e5046b7 --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,27 @@ + + + + + + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + true + true + $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) + + + + + + + + + + + <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> + + + \ No newline at end of file diff --git a/global.json b/src/global.json similarity index 75% rename from global.json rename to src/global.json index 76a2c539e..945bfe269 100644 --- a/global.json +++ b/src/global.json @@ -1,7 +1,7 @@ { "sdk": { "allowPrerelease": true, - "version": "8.0.201", + "version": "8.0.204", "rollForward": "latestFeature" } } \ No newline at end of file diff --git a/tests/Cake.Issues.GitRepository/script-runner/.config/dotnet-tools.json b/tests/Cake.Issues.GitRepository/script-runner/.config/dotnet-tools.json new file mode 100644 index 000000000..7b3469501 --- /dev/null +++ b/tests/Cake.Issues.GitRepository/script-runner/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "4.0.0", + "commands": [ + "dotnet-cake" + ] + } + } + } \ No newline at end of file diff --git a/tests/Cake.Issues.GitRepository/script-runner/build.ps1 b/tests/Cake.Issues.GitRepository/script-runner/build.ps1 new file mode 100644 index 000000000..f22c8110f --- /dev/null +++ b/tests/Cake.Issues.GitRepository/script-runner/build.ps1 @@ -0,0 +1,15 @@ +$ErrorActionPreference = 'Stop' + +$SCRIPT_NAME = "tests.cake" + +Write-Host "Restoring .NET Core tools" +dotnet tool restore +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Running Build" +dotnet cake $SCRIPT_NAME @args +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/Cake.Issues.GitRepository/script-runner/build.sh b/tests/Cake.Issues.GitRepository/script-runner/build.sh new file mode 100644 index 000000000..0c3966375 --- /dev/null +++ b/tests/Cake.Issues.GitRepository/script-runner/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +SCRIPT_NAME="tests.cake" + +echo "Restoring .NET Core tools" +dotnet tool restore + +echo "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap + +echo "Running Build" +dotnet cake $SCRIPT_NAME "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.GitRepository/script-runner/global.json b/tests/Cake.Issues.GitRepository/script-runner/global.json new file mode 100644 index 000000000..c31f98b70 --- /dev/null +++ b/tests/Cake.Issues.GitRepository/script-runner/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.GitRepository/script-runner/nuget.config b/tests/Cake.Issues.GitRepository/script-runner/nuget.config new file mode 100644 index 000000000..62768c3d3 --- /dev/null +++ b/tests/Cake.Issues.GitRepository/script-runner/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.GitRepository/script-runner/testfiles/cake-contrib-small.png b/tests/Cake.Issues.GitRepository/script-runner/testfiles/cake-contrib-small.png new file mode 100644 index 000000000..ecc9fa47c Binary files /dev/null and b/tests/Cake.Issues.GitRepository/script-runner/testfiles/cake-contrib-small.png differ diff --git a/tests/Cake.Issues.GitRepository/script-runner/testfiles/empty.png b/tests/Cake.Issues.GitRepository/script-runner/testfiles/empty.png new file mode 100644 index 000000000..e69de29bb diff --git "a/tests/Cake.Issues.GitRepository/script-runner/testfiles/file-with-umlaut-\303\244.png" "b/tests/Cake.Issues.GitRepository/script-runner/testfiles/file-with-umlaut-\303\244.png" new file mode 100644 index 000000000..ecc9fa47c Binary files /dev/null and "b/tests/Cake.Issues.GitRepository/script-runner/testfiles/file-with-umlaut-\303\244.png" differ diff --git a/tests/Cake.Issues.GitRepository/script-runner/tests.cake b/tests/Cake.Issues.GitRepository/script-runner/tests.cake new file mode 100644 index 000000000..ad3f02296 --- /dev/null +++ b/tests/Cake.Issues.GitRepository/script-runner/tests.cake @@ -0,0 +1,96 @@ +#addin Cake.Issues&prerelease +#addin Cake.Issues.Reporting&prerelease +#addin Cake.Issues.Reporting.Generic&prerelease +#addin Cake.Issues.GitRepository&prerelease + +////////////////////////////////////////////////// +// ARGUMENTS +////////////////////////////////////////////////// + +var target = Argument("target", "Run-All-Tests"); + +////////////////////////////////////////////////// +// SETUP / TEARDOWN +////////////////////////////////////////////////// + +Setup(ctx => +{ +}); + +Teardown(ctx => +{ +}); + +////////////////////////////////////////////////// +// TARGETS +////////////////////////////////////////////////// + +Task("CheckBinaryFilesTrackedByLfs") + .Does(() => +{ + var repoRootDir = MakeAbsolute(Directory("../../../")); + + var issues = + ReadIssues( + GitRepositoryIssuesAliases.GitRepositoryIssues( + Context, + new GitRepositoryIssuesSettings + { + CheckBinaryFilesTrackedByLfs = true + }), + new ReadIssuesSettings(repoRootDir)); + + if (issues.Any(i => i.AffectedFileRelativePath.GetFilename().ToString().Equals("empty.png", StringComparison.InvariantCultureIgnoreCase))) + { + throw new Exception("The empty files should not be treated as binary"); + } + + var reportDir = + repoRootDir.Combine("BuildArtifacts").Combine("TestResults").Combine("Integration"); + var reportFilePath = + reportDir.CombineWithFilePath("CheckBinaryFilesTrackedByLfs.html"); + EnsureDirectoryExists(reportDir); + + CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDiagnostic), + repoRootDir, + reportFilePath); +}); + +Task("CheckFilesPathLength") + .Does(() => +{ + var repoRootDir = MakeAbsolute(Directory("../../../")); + + var issues = + ReadIssues( + GitRepositoryIssuesAliases.GitRepositoryIssues( + Context, + new GitRepositoryIssuesSettings + { + CheckFilesPathLength = true, + MaxFilePathLength = 60 + }), + new ReadIssuesSettings(repoRootDir)); + + var reportDir = + repoRootDir.Combine("BuildArtifacts").Combine("TestResults").Combine("Integration"); + var reportFilePath = + reportDir.CombineWithFilePath("FilePathTooLong.html"); + EnsureDirectoryExists(reportDir); + + CreateIssueReport( + issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDiagnostic), + repoRootDir, + reportFilePath); +}); + +Task("Run-All-Tests") + .IsDependentOn("CheckBinaryFilesTrackedByLfs") + .IsDependentOn("CheckFilesPathLength"); + +////////////////////////////////////////////////// + +RunTarget(target); \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/.config/dotnet-tools.json b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/.config/dotnet-tools.json new file mode 100644 index 000000000..da200cdae --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "4.0.0", + "commands": [ + "dotnet-cake" + ] + } + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/.gitignore b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/.gitignore new file mode 100644 index 000000000..e7c496290 --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/.gitignore @@ -0,0 +1,379 @@ + +# Created by https://www.gitignore.io/api/cake,windows,visualstudio,visualstudiocode + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + + +# End of https://www.gitignore.io/api/cake,windows,visualstudio,visualstudiocode + + +# Project specific folders +BuildArtifacts diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.cake b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.cake new file mode 100644 index 000000000..c02bfed35 --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.cake @@ -0,0 +1,88 @@ +#load "buildData.cake" + +#addin "Cake.Markdownlint" +#addin "Cake.Issues&prerelease" +#addin "Cake.Issues.MsBuild&prerelease" +#addin "Cake.Issues.PullRequests&prerelease" +#addin "Cake.Issues.PullRequests.GitHubActions&prerelease" + +////////////////////////////////////////////////// +// ARGUMENTS +////////////////////////////////////////////////// + +var target = Argument("target", "Default"); + +////////////////////////////////////////////////// +// SETUP / TEARDOWN +////////////////////////////////////////////////// + +Setup(setupContext => +{ + return new BuildData(); +}); + +var repoRootFolder = MakeAbsolute(Directory("./")); +var logPath = repoRootFolder.Combine("BuildArtifacts").Combine("logs"); + +////////////////////////////////////////////////// +// TARGETS +////////////////////////////////////////////////// + +Task("Build") + .Does((data) => +{ + var msBuildLogPath = logPath.CombineWithFilePath("msbuild.binlog"); + var solutionFile = + repoRootFolder + .Combine("src") + .CombineWithFilePath("ClassLibrary1.sln"); + + DotNetRestore(solutionFile.FullPath); + + var settings = + new DotNetMSBuildSettings() + .WithTarget("Rebuild") + .WithLogger( + "BinaryLogger," + Context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll"), + "", + msBuildLogPath.FullPath + ); + + DotNetBuild( + solutionFile.FullPath, + new DotNetBuildSettings + { + MSBuildSettings = settings + }); + + data.AddIssues( + ReadIssues( + MsBuildIssuesFromFilePath( + msBuildLogPath, + MsBuildBinaryLogFileFormat), + repoRootFolder) + ); +}); + +Task("Report-IssuesToBuildServer") + .Does((data) => +{ + ReportIssuesToPullRequest( + data.Issues, + GitHubActionsBuilds(), + repoRootFolder); +}); + +Task("Lint") + .IsDependentOn("Build"); + +// Run issues task by default. +Task("Default") + .IsDependentOn("Lint") + .IsDependentOn("Report-IssuesToBuildServer"); + +////////////////////////////////////////////////// +// EXECUTION +////////////////////////////////////////////////// + +RunTarget(target); \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.ps1 b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.ps1 new file mode 100644 index 000000000..fe6027689 --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.ps1 @@ -0,0 +1,15 @@ +$ErrorActionPreference = 'Stop' + +$SCRIPT_NAME = "build.cake" + +Write-Host "Restoring .NET Core tools" +dotnet tool restore +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Running Build" +dotnet cake $SCRIPT_NAME @args +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.sh b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.sh new file mode 100755 index 000000000..921a3241b --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +SCRIPT_NAME="build.cake" + +echo "Restoring .NET Core tools" +dotnet tool restore + +echo "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap + +echo "Running Build" +dotnet cake $SCRIPT_NAME "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/buildData.cake b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/buildData.cake new file mode 100644 index 000000000..8a22d4145 --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/buildData.cake @@ -0,0 +1,29 @@ +public class BuildData +{ + private readonly List issues = new List(); + + /// + /// Gets issues determined during building. + /// + public IEnumerable Issues + { + get + { + return issues.AsReadOnly(); + } + } + + /// + /// Add issues to . + /// + /// List of issues which should be added. + public void AddIssues(IEnumerable issues) + { + if (issues == null) + { + throw new NullReferenceException(nameof(issues)); + } + + this.issues.AddRange(issues); + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/nuget.config b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/nuget.config new file mode 100644 index 000000000..62768c3d3 --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1.sln b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..9ec4dd90e --- /dev/null +++ b/tests/Cake.Issues.PullRequests.GitHubActions/script-runner/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.0.0 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build.ps1 b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build.ps1 new file mode 100644 index 000000000..478356d64 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build.ps1 @@ -0,0 +1,13 @@ +$RECIPE_PACKAGE_PATH = "packages/cake.issues.reporting.console" +if (Test-Path $RECIPE_PACKAGE_PATH) +{ + Write-Host "Cleaning up cached version of $RECIPE_PACKAGE_PATH..." + Remove-Item $RECIPE_PACKAGE_PATH -Recurse; +} +else +{ + Write-Host "$RECIPE_PACKAGE_PATH not cached..." +} + +dotnet run --project build/Build.csproj -- $args +exit $LASTEXITCODE; \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build.sh b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build.sh new file mode 100644 index 000000000..e0ec44460 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build.sh @@ -0,0 +1,11 @@ + +$RECIPE_PACKAGE_PATH = "packages/cake.issues.reporting.console" +if [ -d "$RECIPE_PACKAGE_PATH" ] +then + echo "Cleaning up cached version of $RECIPE_PACKAGE_PATH..." + rm -Rf $RECIPE_PACKAGE_PATH +else + echo "$RECIPE_PACKAGE_PATH not cached..." +fi + +dotnet run --project ./build/Build.csproj -- "$@" diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/.gitignore b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/.gitignore new file mode 100644 index 000000000..29cb0b57c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/.gitignore @@ -0,0 +1,2 @@ +### Cake ### +tools/* \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/Build.csproj b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/Build.csproj new file mode 100644 index 000000000..6f523215c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/Build.csproj @@ -0,0 +1,13 @@ + + + Exe + net6.0 + $(MSBuildProjectDirectory) + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/Program.cs b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/Program.cs new file mode 100644 index 000000000..4c0b1b3ad --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/build/Program.cs @@ -0,0 +1,51 @@ +using System.Linq; +using Cake.Common.Diagnostics; +using Cake.Core; +using Cake.Frosting; +using Cake.Issues; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Console; + +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) + { + } +} + +[TaskName("Print-Issues")] +public sealed class PrintIssuesTask : FrostingTask +{ + public override void Run(BuildContext context) + { + var issues = context.DeserializeIssuesFromJsonFile(@"../../../../../src/Cake.Issues.Reporting.Console.Tests/Testfiles/issues.json"); + context.Information("Read {0} issues", issues.Count()); + context.CreateIssueReport( + issues, + context.ConsoleIssueReportFormat( + new ConsoleIssueReportFormatSettings + { + ShowProviderSummary = true, + ShowPrioritySummary = true + }), + @"../", + string.Empty); + } +} + +[TaskName("Default")] +[IsDependentOn(typeof(PrintIssuesTask))] +public class DefaultTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/global.json b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/global.json new file mode 100644 index 000000000..c31f98b70 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/frosting/net6.0/nuget.config b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/nuget.config new file mode 100644 index 000000000..d4a4e547e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/frosting/net6.0/nuget.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/.config/dotnet-tools.json b/tests/Cake.Issues.Reporting.Console/script-runner/.config/dotnet-tools.json new file mode 100644 index 000000000..da200cdae --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "4.0.0", + "commands": [ + "dotnet-cake" + ] + } + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/.gitignore b/tests/Cake.Issues.Reporting.Console/script-runner/.gitignore new file mode 100644 index 000000000..e7c496290 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/.gitignore @@ -0,0 +1,379 @@ + +# Created by https://www.gitignore.io/api/cake,windows,visualstudio,visualstudiocode + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + + +# End of https://www.gitignore.io/api/cake,windows,visualstudio,visualstudiocode + + +# Project specific folders +BuildArtifacts diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/build.cake b/tests/Cake.Issues.Reporting.Console/script-runner/build.cake new file mode 100644 index 000000000..838fb082f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/build.cake @@ -0,0 +1,39 @@ +#addin "Cake.Issues&prerelease" +#addin "Cake.Issues.Reporting&prerelease" +#addin "Cake.Issues.Reporting.Console&prerelease" + +////////////////////////////////////////////////// +// ARGUMENTS +////////////////////////////////////////////////// + +var target = Argument("target", "Default"); + +////////////////////////////////////////////////// +// TARGETS +////////////////////////////////////////////////// + +Task("Print-Issues") + .Does(() => +{ + var issues = DeserializeIssuesFromJsonFile(@"../../../src/Cake.Issues.Reporting.Console.Tests/Testfiles/issues.json"); + Information("Read {0} issues", issues.Count()); + CreateIssueReport( + issues, + ConsoleIssueReportFormat( + new ConsoleIssueReportFormatSettings + { + ShowProviderSummary = true, + ShowPrioritySummary = true + }), + @".", + string.Empty); +}); + +Task("Default") + .IsDependentOn("Print-Issues"); + +////////////////////////////////////////////////// +// EXECUTION +////////////////////////////////////////////////// + +RunTarget(target); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/build.ps1 b/tests/Cake.Issues.Reporting.Console/script-runner/build.ps1 new file mode 100644 index 000000000..fe6027689 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/build.ps1 @@ -0,0 +1,15 @@ +$ErrorActionPreference = 'Stop' + +$SCRIPT_NAME = "build.cake" + +Write-Host "Restoring .NET Core tools" +dotnet tool restore +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Running Build" +dotnet cake $SCRIPT_NAME @args +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/build.sh b/tests/Cake.Issues.Reporting.Console/script-runner/build.sh new file mode 100644 index 000000000..921a3241b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +SCRIPT_NAME="build.cake" + +echo "Restoring .NET Core tools" +dotnet tool restore + +echo "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap + +echo "Running Build" +dotnet cake $SCRIPT_NAME "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/global.json b/tests/Cake.Issues.Reporting.Console/script-runner/global.json new file mode 100644 index 000000000..c31f98b70 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Console/script-runner/nuget.config b/tests/Cake.Issues.Reporting.Console/script-runner/nuget.config new file mode 100644 index 000000000..62768c3d3 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Console/script-runner/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build.ps1 b/tests/Cake.Issues.Reporting.Generic/frosting/build.ps1 new file mode 100644 index 000000000..a7077190a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build.ps1 @@ -0,0 +1,2 @@ +dotnet run --project build/Build.csproj -- $args +exit $LASTEXITCODE; \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build.sh b/tests/Cake.Issues.Reporting.Generic/frosting/build.sh new file mode 100644 index 000000000..dfd6b854b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build.sh @@ -0,0 +1 @@ +dotnet run --project ./build/Build.csproj -- "$@" diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/Build.csproj b/tests/Cake.Issues.Reporting.Generic/frosting/build/Build.csproj new file mode 100644 index 000000000..2cdb42cf7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/Build.csproj @@ -0,0 +1,13 @@ + + + Exe + net6.0 + $(MSBuildProjectDirectory) + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/BuildContext.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/BuildContext.cs new file mode 100644 index 000000000..974f35ae4 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/BuildContext.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Cake.Common.IO; +using Cake.Core; +using Cake.Core.IO; +using Cake.Frosting; +using Cake.Issues; + +public class BuildContext : FrostingContext +{ + public DirectoryPath RepoRootFolder { get; } + public DirectoryPath SourceFolder { get; } + public DirectoryPath DocsFolder { get; } + public DirectoryPath TemplateGalleryFolder { get; } + public List Issues { get; } + + public BuildContext(ICakeContext context) + : base(context) + { + this.RepoRootFolder = context.MakeAbsolute(context.Directory("./../..")); + this.SourceFolder = this.RepoRootFolder.Combine("src"); + this.DocsFolder = this.RepoRootFolder.Combine("docs"); + this.TemplateGalleryFolder = this.RepoRootFolder.Combine("../../docs/input/docs/report-formats/generic/templates"); + + this.Issues = new List(); + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/Program.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/Program.cs new file mode 100644 index 000000000..53c8fe576 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/Program.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Cake.Frosting; + +public static class Program +{ + public static int Main(string[] args) + { + return new CakeHost() + .UseContext() + .Run(args); + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/nuget.config b/tests/Cake.Issues.Reporting.Generic/frosting/build/nuget.config new file mode 100644 index 000000000..257d464ee --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/nuget.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/DefaultTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/DefaultTask.cs new file mode 100644 index 000000000..6a53e8860 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/DefaultTask.cs @@ -0,0 +1,7 @@ +using Cake.Frosting; + +[TaskName("Default")] +[IsDependentOn(typeof(CreateReportsTask))] +public class DefaultTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/analyze/AnalyzeTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/analyze/AnalyzeTask.cs new file mode 100644 index 000000000..8dcc1f6f8 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/analyze/AnalyzeTask.cs @@ -0,0 +1,7 @@ +using Cake.Frosting; + +[TaskName("Analyze")] +[IsDependentOn(typeof(CreateCustomIssuesTask))] +public class AnalyzeTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/analyze/CreateCustomIssuesTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/analyze/CreateCustomIssuesTask.cs new file mode 100644 index 000000000..b911114b1 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/analyze/CreateCustomIssuesTask.cs @@ -0,0 +1,21 @@ +using Cake.Frosting; +using Cake.Issues; + +[TaskName("Create-CustomIssues")] +public class CreateCustomIssuesTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.Issues.Add( + context.NewIssue( + "Something went wrong", + "MyCakeScript", + "My Cake Script") + .WithMessageInHtmlFormat("Something went wrong") + .WithMessageInMarkdownFormat("Something went **wrong**") + .InFile("myfile.txt", 42) + .WithPriority(IssuePriority.Warning) + .Create() + ); + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDataTableDefaultTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDataTableDefaultTask.cs new file mode 100644 index 000000000..138314f56 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDataTableDefaultTask.cs @@ -0,0 +1,18 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDataTable-Default")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDataTableDefaultTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDataTable), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldatatable-demo-default.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDataTableTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDataTableTask.cs new file mode 100644 index 000000000..614bda40e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDataTableTask.cs @@ -0,0 +1,7 @@ +using Cake.Frosting; + +[TaskName("Create-Reports-HtmlDataTable")] +[IsDependentOn(typeof(CreateReportsHtmlDataTableDefaultTask))] +public class CreateReportsHtmlDataTableTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDiagnosticDefaultTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDiagnosticDefaultTask.cs new file mode 100644 index 000000000..fbe6f4264 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDiagnosticDefaultTask.cs @@ -0,0 +1,18 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDiagnostic-Default")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDiagnosticDefaultTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDiagnostic), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldiagnostic-demo-default.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDiagnosticTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDiagnosticTask.cs new file mode 100644 index 000000000..524041971 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDiagnosticTask.cs @@ -0,0 +1,7 @@ +using Cake.Frosting; + +[TaskName("Create-Reports-HtmlDiagnostic")] +[IsDependentOn(typeof(CreateReportsHtmlDiagnosticDefaultTask))] +public class CreateReportsHtmlDiagnosticTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridAdditionalColumnsTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridAdditionalColumnsTask.cs new file mode 100644 index 000000000..c06eba73f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridAdditionalColumnsTask.cs @@ -0,0 +1,36 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; +using System.Collections.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Additional-Columns")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridAdditionalColumnsTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption( + HtmlDxDataGridOption.AdditionalColumns, + new List + { + new HtmlDxDataGridColumnDescription( + "IsSrcFolder", + issue => + { + return issue.AffectedFileRelativePath?.FullPath.StartsWith("src/"); + }) + { + Caption = "Source Folder", + } + })), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-additionalcolumns.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridChangeTitleTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridChangeTitleTask.cs new file mode 100644 index 000000000..ca624f973 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridChangeTitleTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Change-Title")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridChangeTitleTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Title, "My Custom Title")), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-changetitle.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridCustomExportFilenameTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridCustomExportFilenameTask.cs new file mode 100644 index 000000000..81b38d95e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridCustomExportFilenameTask.cs @@ -0,0 +1,23 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Custom-Export-Filename")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridCustomExportFilenameTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true) + .WithOption(HtmlDxDataGridOption.ExportFileName, "custom-filename")), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-customexportfilename.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridCustomScriptLocationTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridCustomScriptLocationTask.cs new file mode 100644 index 000000000..da863c41c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridCustomScriptLocationTask.cs @@ -0,0 +1,25 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Custom-Script-Location")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridCustomScriptLocationTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.JQueryLocation, "https://ajax.aspnetcdn.com/ajax/jquery/") + .WithOption(HtmlDxDataGridOption.JQueryVersion, "3.1.0") + .WithOption(HtmlDxDataGridOption.DevExtremeLocation, "https://cdn3.devexpress.com/jslib/") + .WithOption(HtmlDxDataGridOption.DevExtremeVersion, "18.2.3")), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-customscriptlocation.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDefaultTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDefaultTask.cs new file mode 100644 index 000000000..472aef863 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDefaultTask.cs @@ -0,0 +1,19 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Default")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridDefaultTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-default.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableFilteringTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableFilteringTask.cs new file mode 100644 index 000000000..8a5ac24c6 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableFilteringTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Disable-Filtering")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridDisableFilteringTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableFiltering, false)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disablefiltering.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableGroupingTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableGroupingTask.cs new file mode 100644 index 000000000..768fdc54c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableGroupingTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Disable-Grouping")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridDisableGroupingTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableGrouping, false)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disablegrouping.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableHeaderTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableHeaderTask.cs new file mode 100644 index 000000000..7fd2661a3 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableHeaderTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Disable-Header")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridDisableHeaderTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.ShowHeader, false)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disableheader.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableSearchingTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableSearchingTask.cs new file mode 100644 index 000000000..a090a4d51 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridDisableSearchingTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Disable-Searching")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridDisableSearchingTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableSearching, false)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disablesearching.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridEnableExportingTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridEnableExportingTask.cs new file mode 100644 index 000000000..57964fd79 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridEnableExportingTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Enable-Exporting")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridEnableExportingTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-enableexporting.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridExportFormatPdfTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridExportFormatPdfTask.cs new file mode 100644 index 000000000..be1851b7f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridExportFormatPdfTask.cs @@ -0,0 +1,23 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Export-Format-Pdf")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridExportFormatPdfTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true) + .WithOption(HtmlDxDataGridOption.ExportFormat, HtmlDxDataGridExportFormat.Pdf)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-exportformat-pdf.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridExportFormatXlsxTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridExportFormatXlsxTask.cs new file mode 100644 index 000000000..c9488f81f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridExportFormatXlsxTask.cs @@ -0,0 +1,23 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Export-Format-Xlsx")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridExportFormatXlsxTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true) + .WithOption(HtmlDxDataGridOption.ExportFormat, HtmlDxDataGridExportFormat.Excel)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-exportformat-xlsx.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridGroupingTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridGroupingTask.cs new file mode 100644 index 000000000..bbb4a7de6 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridGroupingTask.cs @@ -0,0 +1,23 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; +using System.Collections.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Grouping")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridGroupingTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.GroupedColumns, new List { ReportColumn.RuleId })), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-grouping.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridHideColumnsTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridHideColumnsTask.cs new file mode 100644 index 000000000..935b3ac84 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridHideColumnsTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Hide-Columns")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridHideColumnsTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.LineVisible, false)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-columnhiding.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridSortingTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridSortingTask.cs new file mode 100644 index 000000000..e4d34dd06 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridSortingTask.cs @@ -0,0 +1,24 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; +using System.Collections.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Sorting")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridSortingTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.SortedColumns, new List { ReportColumn.RuleId }) + .WithOption(HtmlDxDataGridOption.RuleIdSortOrder, ColumnSortOrder.Descending)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-sorting.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridTask.cs new file mode 100644 index 000000000..ea282a0a9 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridTask.cs @@ -0,0 +1,52 @@ +using Cake.Frosting; + +[TaskName("Create-Reports-HtmlDxDataGrid")] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridDefaultTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeLightTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeDarkTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeContrastTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeCarmineTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeDarkMoonTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeSoftBlueTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeDarkVioletTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeGreenMistTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeLightCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeDarkCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeContrastCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialBlueLightTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialLimeLightTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialOrangeLightTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialPurpleLightTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialTealLightTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialBlueDarkTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialLimeDarkTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialTealDarkTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialBlueLightCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialLimeLightCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialOrangeLightCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialPurpleLightCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialTealLightCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialBlueDarkCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialLimeDarkCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridThemeMaterialTealDarkCompactTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridHideColumnsTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridAdditionalColumnsTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridSortingTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridGroupingTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridDisableGroupingTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridChangeTitleTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridDisableHeaderTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridDisableFilteringTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridDisableSearchingTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridCustomScriptLocationTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridEnableExportingTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridExportFormatXlsxTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridExportFormatPdfTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridCustomExportFilenameTask))] +public class CreateReportsHtmlDxDataGridTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeCarmineTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeCarmineTask.cs new file mode 100644 index 000000000..03a4ab8fd --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeCarmineTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-Carmine")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeCarmineTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Carmine)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-carmine.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeContrastCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeContrastCompactTask.cs new file mode 100644 index 000000000..4c3425ff9 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeContrastCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-ContrastCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeContrastCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.ContrastCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-contrastcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeContrastTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeContrastTask.cs new file mode 100644 index 000000000..b454e8f07 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeContrastTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-Contrast")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeContrastTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Contrast)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-contrast.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkCompactTask.cs new file mode 100644 index 000000000..c23ee9e0e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-DarkCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeDarkCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.DarkCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-darkcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkMoonTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkMoonTask.cs new file mode 100644 index 000000000..8ef779854 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkMoonTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-DarkMoon")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeDarkMoonTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.DarkMoon)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-darkmoon.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkTask.cs new file mode 100644 index 000000000..8f60ad850 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-Dark")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeDarkTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Dark)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-dark.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkViolet.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkViolet.cs new file mode 100644 index 000000000..2363b8b3f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeDarkViolet.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-DarkViolet")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeDarkVioletTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.DarkViolet)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-darkviolet.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeGreenMistTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeGreenMistTask.cs new file mode 100644 index 000000000..7b5105248 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeGreenMistTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-GreenMist")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeGreenMistTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.GreenMist)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-greenmist.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeLightCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeLightCompactTask.cs new file mode 100644 index 000000000..09462fc79 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeLightCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-LightCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeLightCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.LightCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-lightcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeLightTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeLightTask.cs new file mode 100644 index 000000000..6d59f7c9b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeLightTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-Light")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeLightTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Light)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-light.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueDarkCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueDarkCompactTask.cs new file mode 100644 index 000000000..25638452b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueDarkCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueDarkCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialBlueDarkCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueDarkCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluedarkcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueDarkTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueDarkTask.cs new file mode 100644 index 000000000..0901e2aac --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueDarkTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueDark")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialBlueDarkTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueDark)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluedark.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueLightCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueLightCompactTask.cs new file mode 100644 index 000000000..c059d2772 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueLightCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueLightCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialBlueLightCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLightCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluelightcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueLightTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueLightTask.cs new file mode 100644 index 000000000..13f57062e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialBlueLightTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueLight")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialBlueLightTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLight)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluelight.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeDarkCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeDarkCompactTask.cs new file mode 100644 index 000000000..357eb9915 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeDarkCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeDarkCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialLimeDarkCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeDarkCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimedarkcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeDarkTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeDarkTask.cs new file mode 100644 index 000000000..6073815c5 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeDarkTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeDark")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialLimeDarkTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeDark)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimedark.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeLightCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeLightCompactTask.cs new file mode 100644 index 000000000..3d4dd053b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeLightCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeLightCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialLimeLightCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeLightCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimelightcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeLightTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeLightTask.cs new file mode 100644 index 000000000..29c99502e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialLimeLightTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeLight")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialLimeLightTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeLight)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimelight.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkCompactTask.cs new file mode 100644 index 000000000..5b28d1dc3 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeDarkCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeDarkCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangedarkcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkTask.cs new file mode 100644 index 000000000..a744dbe7f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeDark")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialOrangeDarkTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeDark)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangedark.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeLightCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeLightCompactTask.cs new file mode 100644 index 000000000..6fa37e095 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeLightCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeLightCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialOrangeLightCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeLightCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangelightcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeLightTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeLightTask.cs new file mode 100644 index 000000000..cd43e5ffb --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialOrangeLightTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeLight")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialOrangeLightTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeLight)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangelight.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkCompactTask.cs new file mode 100644 index 000000000..bf2b48360 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleDarkCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleDarkCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurpledarkcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkTask.cs new file mode 100644 index 000000000..492ff26fb --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleDark")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialPurpleDarkTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleDark)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurpledark.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleLightCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleLightCompactTask.cs new file mode 100644 index 000000000..e5b5cbe51 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleLightCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleLightCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialPurpleLightCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleLightCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurplelightcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleLightTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleLightTask.cs new file mode 100644 index 000000000..e92952b43 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialPurpleLightTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleLight")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialPurpleLightTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleLight)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurplelight.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealDarkCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealDarkCompactTask.cs new file mode 100644 index 000000000..3838499e4 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealDarkCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealDarkCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialTealDarkCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealDarkCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialtealdarkcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealDarkTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealDarkTask.cs new file mode 100644 index 000000000..dc6cdcd98 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealDarkTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealDark")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialTealDarkTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealDark)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialtealdark.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealLightCompactTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealLightCompactTask.cs new file mode 100644 index 000000000..d9f061b11 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealLightCompactTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealLightCompact")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialTealLightCompactTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealLightCompact)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialteallightcompact.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealLightTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealLightTask.cs new file mode 100644 index 000000000..66fcc3c4b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeMaterialTealLightTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealLight")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeMaterialTealLightTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealLight)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialteallight.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeSoftBlueTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeSoftBlueTask.cs new file mode 100644 index 000000000..c03c9169d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsHtmlDxDataGridThemeSoftBlueTask.cs @@ -0,0 +1,22 @@ +using Cake.Frosting; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Generic; + +[TaskName("Create-Reports-HtmlDxDataGrid-Theme-SoftBlue")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReportsHtmlDxDataGridThemeSoftBlueTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.CreateIssueReport( + context.Issues, + context.GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => + settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.SoftBlue)), + context.RepoRootFolder, + context.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-softblue.html")); + + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsTask.cs b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsTask.cs new file mode 100644 index 000000000..f4fccbb10 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/build/tasks/create-reports/CreateReportsTask.cs @@ -0,0 +1,9 @@ +using Cake.Frosting; + +[TaskName("Create-ReportsTask")] +[IsDependentOn(typeof(CreateReportsHtmlDiagnosticTask))] +[IsDependentOn(typeof(CreateReportsHtmlDataTableTask))] +[IsDependentOn(typeof(CreateReportsHtmlDxDataGridTask))] +public class CreateReportsTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/docs/index.md b/tests/Cake.Issues.Reporting.Generic/frosting/docs/index.md new file mode 100644 index 000000000..68eae7083 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/docs/index.md @@ -0,0 +1,7 @@ +# foo +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum dictum mauris, sed feugiat nibh rutrum eget. Fusce sed purus nec sem faucibus semper sed id est. Cras vestibulum leo nec ipsum posuere eleifend. Nullam iaculis quam in sapien efficitur consequat. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vivamus pulvinar bibendum sapien ac ultrices. Sed imperdiet mi non felis imperdiet, at interdum ante volutpat. Pellentesque eu cursus dolor, non iaculis ipsum. Quisque in tortor viverra, sodales nibh vitae, vehicula urna. Integer dolor mauris, condimentum ac accumsan quis, placerat eget tellus. Duis volutpat interdum nisi, vel efficitur nisl viverra vitae. Maecenas eget lacus vel lacus congue lobortis. Etiam ornare dictum nulla nec commodo. + +# bar +``` +Praesent euismod est vel quam volutpat ultrices. Cras luctus lorem quis nibh tincidunt, a auctor velit fermentum. Cras et nisl neque. Sed mi lorem, efficitur et purus eu, vehicula ornare felis. Aliquam sagittis ultricies sem, nec dignissim erat porta at. Suspendisse in justo lacus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque ornare neque porttitor tortor auctor lobortis posuere id dui. Phasellus et felis a nibh viverra cursus ut blandit ante. Suspendisse lacus tortor, pharetra non pulvinar vulputate, semper sed augue. Aenean feugiat finibus quam quis iaculis. Maecenas ac quam quis risus scelerisque rhoncus. Donec eget aliquam metus. Nam feugiat sem dui, quis consectetur lorem lobortis in. Maecenas eu bibendum sapien. +``` \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/global.json b/tests/Cake.Issues.Reporting.Generic/frosting/global.json new file mode 100644 index 000000000..198c2bcb2 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.420", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1.sln b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..4539075f9 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.3.2 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/packages.config b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/packages.config new file mode 100644 index 000000000..719f545c7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/frosting/src/ClassLibrary1/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/.config/dotnet-tools.json b/tests/Cake.Issues.Reporting.Generic/script-runner/.config/dotnet-tools.json new file mode 100644 index 000000000..da200cdae --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "4.0.0", + "commands": [ + "dotnet-cake" + ] + } + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/.gitignore b/tests/Cake.Issues.Reporting.Generic/script-runner/.gitignore new file mode 100644 index 000000000..6d7ad9236 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/.gitignore @@ -0,0 +1,345 @@ + +# Created by https://www.gitignore.io/api/cake,visualstudio + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +*.pubxml.user + + +# End of https://www.gitignore.io/api/cake,visualstudio diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/.markdownlint.json b/tests/Cake.Issues.Reporting.Generic/script-runner/.markdownlint.json new file mode 100644 index 000000000..5bcc68ac6 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/.markdownlint.json @@ -0,0 +1,10 @@ +{ + "default": true, + "MD003": { "style": "atx" }, + "MD004": { "style": "asterisk" }, + "MD007": { "indent": 4 }, + "MD009": { "br_spaces": 2 }, + "MD013": { "line_length": 100, "tables": false, "code_blocks": false }, + "MD029": { "style": "ordered" }, + "MD035": { "style": "----------------------------------------------------------------------------------------------------" } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build.cake new file mode 100644 index 000000000..aa947e3bd --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build.cake @@ -0,0 +1,45 @@ +#addin "Cake.Markdownlint" +#addin "Cake.Issues&prerelease" +#addin "Cake.Issues.MsBuild&prerelease" +#addin "Cake.Issues.Markdownlint&prerelease" +#addin "Cake.Issues.DupFinder&prerelease" +#addin "Cake.Issues.InspectCode&prerelease" +#addin "Cake.Issues.Reporting&prerelease" +#addin "Cake.Issues.Reporting.Generic&prerelease" + +#tool nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2021.2.2 + +#load build/build/build.cake +#load build/analyze/analyze.cake +#load build/create-reports/create-reports.cake + +var target = Argument("target", "Default"); + +public class BuildData +{ + public DirectoryPath RepoRootFolder { get; } + public DirectoryPath SourceFolder { get; } + public DirectoryPath DocsFolder { get; } + public DirectoryPath TemplateGalleryFolder { get; } + public List Issues { get; } + + public BuildData(ICakeContext context) + { + this.RepoRootFolder = context.MakeAbsolute(context.Directory("./")); + this.SourceFolder = this.RepoRootFolder.Combine("src"); + this.DocsFolder = this.RepoRootFolder.Combine("docs"); + this.TemplateGalleryFolder = this.RepoRootFolder.Combine("../../../docs/input/docs/report-formats/generic/templates"); + + this.Issues = new List(); + } +} + +Setup(setupContext => +{ + return new BuildData(setupContext); +}); + +Task("Default") + .IsDependentOn("Create-Reports"); + +RunTarget(target); diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build.ps1 b/tests/Cake.Issues.Reporting.Generic/script-runner/build.ps1 new file mode 100644 index 000000000..fe6027689 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build.ps1 @@ -0,0 +1,15 @@ +$ErrorActionPreference = 'Stop' + +$SCRIPT_NAME = "build.cake" + +Write-Host "Restoring .NET Core tools" +dotnet tool restore +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Running Build" +dotnet cake $SCRIPT_NAME @args +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build.sh b/tests/Cake.Issues.Reporting.Generic/script-runner/build.sh new file mode 100644 index 000000000..921a3241b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +SCRIPT_NAME="build.cake" + +echo "Restoring .NET Core tools" +dotnet tool restore + +echo "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap + +echo "Running Build" +dotnet cake $SCRIPT_NAME "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/analyze.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/analyze.cake new file mode 100644 index 000000000..f29adcd29 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/analyze.cake @@ -0,0 +1,11 @@ +#load dupfinder.cake +#load inspectcode.cake +#load markdownlint.cake +#load custom-issue.cake + +Task("Analyze") + .IsDependentOn("Build") + .IsDependentOn("Run-DupFinder") + .IsDependentOn("Run-InspectCode") + .IsDependentOn("Lint-Documentation") + .IsDependentOn("Create-CustomIssues"); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/custom-issue.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/custom-issue.cake new file mode 100644 index 000000000..de300b98f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/custom-issue.cake @@ -0,0 +1,16 @@ +Task("Create-CustomIssues") + .Description("Creates additional issues in the build script") + .Does(data => +{ + data.Issues.Add( + NewIssue( + "Something went wrong", + "MyCakeScript", + "My Cake Script") + .WithMessageInHtmlFormat("Something went wrong") + .WithMessageInMarkdownFormat("Something went **wrong**") + .InFile("myfile.txt", 42) + .WithPriority(IssuePriority.Warning) + .Create() + ); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/dupfinder.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/dupfinder.cake new file mode 100644 index 000000000..89bdc947e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/dupfinder.cake @@ -0,0 +1,33 @@ +Task("Run-DupFinder") + .Description("Runs JetBrains DupFinder analysis") + .WithCriteria((context) => context.IsRunningOnWindows(), "DupFinder is only supported on Windows.") + .Does((data) => +{ + var dupFinderLogFilePath = + data.RepoRootFolder.CombineWithFilePath("dupFinder.log"); + + // Run DupFinder + var settings = new DupFinderSettings() { + OutputFile = dupFinderLogFilePath + }; + + DupFinder( + data.SourceFolder.CombineWithFilePath("ClassLibrary1.sln"), + settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Generic"), + "develop", + "demos/script-runner" + ) + }; + + data.Issues.AddRange( + ReadIssues( + DupFinderIssuesFromFilePath(dupFinderLogFilePath), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/inspectcode.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/inspectcode.cake new file mode 100644 index 000000000..a18bdd482 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/inspectcode.cake @@ -0,0 +1,31 @@ +Task("Run-InspectCode") + .Description("Runs JetBrains InspectCode analysis") + .WithCriteria((context) => context.IsRunningOnWindows(), "InspectCode is only supported on Windows.") + .Does(data => +{ + var inspectCodeLogFilePath = + data.RepoRootFolder.CombineWithFilePath("inspectCode.log"); + + // Run InspectCode + var settings = new InspectCodeSettings() { + OutputFile = inspectCodeLogFilePath + }; + + InspectCode(data.SourceFolder.CombineWithFilePath("ClassLibrary1.sln"), settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Generic"), + "develop", + "demos/script-runner" + ) + }; + + data.Issues.AddRange( + ReadIssues( + InspectCodeIssuesFromFilePath(inspectCodeLogFilePath), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/markdownlint.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/markdownlint.cake new file mode 100644 index 000000000..7203b37db --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/analyze/markdownlint.cake @@ -0,0 +1,69 @@ +Task("Lint-Documentation") + .IsDependentOn("Lint-DemoDocumentation") + .IsDependentOn("Lint-TemplateGalleryDocumentation"); + +Task("Lint-DemoDocumentation") + .Description("Runs Markdownint on demo documentation") + .Does(data => +{ + var markdownLintLogFilePath = data.RepoRootFolder.CombineWithFilePath("markdown.log"); + + // Run markdownlint + var settings = + MarkdownlintNodeJsRunnerSettings.ForDirectory(data.DocsFolder); + settings.OutputFile = markdownLintLogFilePath; + settings.ThrowOnIssue = false; + RunMarkdownlintNodeJs(settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + Run = "Demos documentation", + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Generic"), + "develop", + "demos/script-runner" + ) + }; + + data.Issues.AddRange( + ReadIssues( + MarkdownlintIssuesFromFilePath( + markdownLintLogFilePath, + MarkdownlintCliLogFileFormat), + readIssuesSettings)); +}); + +Task("Lint-TemplateGalleryDocumentation") + .Description("Runs Markdownint on template gallery documentation") + .Does(data => +{ + var markdownLintLogFilePath = data.RepoRootFolder.CombineWithFilePath("markdown.log"); + + // Run markdownlint + var settings = + MarkdownlintNodeJsRunnerSettings.ForDirectory(data.TemplateGalleryFolder); + settings.OutputFile = markdownLintLogFilePath; + settings.ThrowOnIssue = false; + RunMarkdownlintNodeJs(settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + Run = "Template gallery documentation", + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Generic"), + "develop", + "docs" + ) + }; + + data.Issues.AddRange( + ReadIssues( + MarkdownlintIssuesFromFilePath( + markdownLintLogFilePath, + MarkdownlintCliLogFileFormat), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/build/build.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/build/build.cake new file mode 100644 index 000000000..457356c35 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/build/build.cake @@ -0,0 +1,56 @@ +Task("Build") + .Description("Builds the solution") + .Does(data => +{ + var solutionFile = data.SourceFolder.CombineWithFilePath("ClassLibrary1.sln"); + var msBuildLogFilePath = data.RepoRootFolder.CombineWithFilePath("msbuild.binlog"); + +#if NETCOREAPP + DotNetRestore(solutionFile.FullPath); + + var settings = + new DotNetMSBuildSettings() + .WithTarget("Rebuild") + .WithLogger( + "BinaryLogger," + Context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll"), + "", + msBuildLogFilePath.FullPath + ); + + DotNetBuild( + solutionFile.FullPath, + new DotNetBuildSettings + { + MSBuildSettings = settings + }); +#else + NuGetRestore(solutionFile); + + var settings = + new MSBuildSettings() + .WithTarget("Rebuild") + .WithLogger( + Context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll").FullPath, + "BinaryLogger", + msBuildLogFilePath.FullPath); + MSBuild(solutionFile, settings); +#endif + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Generic"), + "develop", + "demos/script-runner" + ) + }; + + data.Issues.AddRange( + ReadIssues( + MsBuildIssuesFromFilePath( + msBuildLogFilePath, + MsBuildBinaryLogFileFormat), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldatatable-default.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldatatable-default.cake new file mode 100644 index 000000000..df96d7237 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldatatable-default.cake @@ -0,0 +1,11 @@ +Task("Create-Reports-HtmlDataTable-Default") + .Description("Creates HtmlDataTable default demo report") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDataTable), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldatatable-demo-default.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldatatable.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldatatable.cake new file mode 100644 index 000000000..fb753ae61 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldatatable.cake @@ -0,0 +1,5 @@ +#load create-reports-htmldatatable-default.cake + +Task("Create-Reports-HtmlDataTable") + .Description("Creates HtmlDataTable demo reports") + .IsDependentOn("Create-Reports-HtmlDataTable-Default"); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldiagnostic-default.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldiagnostic-default.cake new file mode 100644 index 000000000..460a5110c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldiagnostic-default.cake @@ -0,0 +1,11 @@ +Task("Create-Reports-HtmlDiagnostic-Default") + .Description("Creates HtmlDiagnostic default demo report") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDiagnostic), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldiagnostic-demo-default.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldiagnostic.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldiagnostic.cake new file mode 100644 index 000000000..454fb845b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldiagnostic.cake @@ -0,0 +1,5 @@ +#load create-reports-htmldiagnostic-default.cake + +Task("Create-Reports-HtmlDiagnostic") + .Description("Creates HtmlDiagnostic demo reports") + .IsDependentOn("Create-Reports-HtmlDiagnostic-Default"); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-additional-columns.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-additional-columns.cake new file mode 100644 index 000000000..b4c3ac1de --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-additional-columns.cake @@ -0,0 +1,27 @@ +Task("Create-Reports-HtmlDxDataGrid-Additional-Columns") + .Description("Creates HtmlDxDataGrid demo report showing how to add additional columns to a report") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption( + HtmlDxDataGridOption.AdditionalColumns, + new List + { + new HtmlDxDataGridColumnDescription( + "IsSrcFolder", + issue => + { + return issue.AffectedFileRelativePath?.FullPath.StartsWith("src/"); + }) + { + Caption = "Source Folder", + } + })), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-additionalcolumns.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-change-title.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-change-title.cake new file mode 100644 index 000000000..d8a69295b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-change-title.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Change-Title") + .Description("Creates HtmlDxDataGrid demo report showing how to change report title") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Title, "My Custom Title")), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-changetitle.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-custom-export-filename.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-custom-export-filename.cake new file mode 100644 index 000000000..d63849659 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-custom-export-filename.cake @@ -0,0 +1,15 @@ +Task("Create-Reports-HtmlDxDataGrid-Custom-Export-Filename") + .Description("Creates HtmlDxDataGrid demo report showing how to change default name of exported file") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true) + .WithOption(HtmlDxDataGridOption.ExportFileName, "custom-filename")), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-customexportfilename.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-custom-script-location.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-custom-script-location.cake new file mode 100644 index 000000000..477bfabd7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-custom-script-location.cake @@ -0,0 +1,17 @@ +Task("Create-Reports-HtmlDxDataGrid-Custom-Script-Location") + .Description("Creates HtmlDxDataGrid demo report showing how to use custom script location and version") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.JQueryLocation, "https://ajax.aspnetcdn.com/ajax/jquery/") + .WithOption(HtmlDxDataGridOption.JQueryVersion, "3.1.0") + .WithOption(HtmlDxDataGridOption.DevExtremeLocation, "https://cdn3.devexpress.com/jslib/") + .WithOption(HtmlDxDataGridOption.DevExtremeVersion, "18.2.3")), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-customscriptlocation.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-default.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-default.cake new file mode 100644 index 000000000..b866d27be --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-default.cake @@ -0,0 +1,11 @@ +Task("Create-Reports-HtmlDxDataGrid-Default") + .Description("Creates HtmlDxDataGrid default demo report") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate(GenericIssueReportTemplate.HtmlDxDataGrid), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-default.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-filtering.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-filtering.cake new file mode 100644 index 000000000..8a5b74954 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-filtering.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Disable-Filtering") + .Description("Creates HtmlDxDataGrid demo report showing how to disable filtering functionality") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableFiltering, false)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disablefiltering.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-grouping.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-grouping.cake new file mode 100644 index 000000000..db4a13085 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-grouping.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Disable-Grouping") + .Description("Creates HtmlDxDataGrid demo report showing how to disable grouping functionality") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableGrouping, false)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disablegrouping.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-header.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-header.cake new file mode 100644 index 000000000..67b14837f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-header.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Disable-Header") + .Description("Creates HtmlDxDataGrid demo report showing how to disable the report header") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.ShowHeader, false)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disableheader.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-searching.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-searching.cake new file mode 100644 index 000000000..3e1b85768 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-disable-searching.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Disable-Searching") + .Description("Creates HtmlDxDataGrid demo report showing how to disable searching functionality") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableSearching, false)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-disablesearching.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-enable-exporting.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-enable-exporting.cake new file mode 100644 index 000000000..125335a62 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-enable-exporting.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Enable-Exporting") + .Description("Creates HtmlDxDataGrid demo report showing how to enable exporting functionality") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-enableexporting.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-exportformat-pdf.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-exportformat-pdf.cake new file mode 100644 index 000000000..c81f4b678 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-exportformat-pdf.cake @@ -0,0 +1,15 @@ +Task("Create-Reports-HtmlDxDataGrid-ExportFormat-Pdf") + .Description("Creates HtmlDxDataGrid demo report showing how to enable PDF export") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true) + .WithOption(HtmlDxDataGridOption.ExportFormat, HtmlDxDataGridExportFormat.Pdf)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-exportformat-pdf.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-exportformat-xlsx.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-exportformat-xlsx.cake new file mode 100644 index 000000000..09dbca8da --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-exportformat-xlsx.cake @@ -0,0 +1,15 @@ +Task("Create-Reports-HtmlDxDataGrid-ExportFormat-Xlsx") + .Description("Creates HtmlDxDataGrid demo report showing how to enable Excel export") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.EnableExporting, true) + .WithOption(HtmlDxDataGridOption.ExportFormat, HtmlDxDataGridExportFormat.Excel)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-exportformat-xlsx.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-grouping.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-grouping.cake new file mode 100644 index 000000000..ce43a73ef --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-grouping.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Grouping") + .Description("Creates HtmlDxDataGrid demo report showing how to define column grouping") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.GroupedColumns, new List { ReportColumn.RuleId })), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-grouping.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-hide-columns.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-hide-columns.cake new file mode 100644 index 000000000..297fa39f0 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-hide-columns.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Hide-Columns") + .Description("Creates HtmlDxDataGrid demo report showing how to hide columns") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.LineVisible, false)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-columnhiding.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-sorting.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-sorting.cake new file mode 100644 index 000000000..02c364ab2 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-sorting.cake @@ -0,0 +1,15 @@ +Task("Create-Reports-HtmlDxDataGrid-Sorting") + .Description("Creates HtmlDxDataGrid demo report showing how to change column sorting") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.SortedColumns, new List { ReportColumn.RuleId }) + .WithOption(HtmlDxDataGridOption.RuleIdSortOrder, ColumnSortOrder.Descending)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-sorting.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-carmine.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-carmine.cake new file mode 100644 index 000000000..a7bc70ff1 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-carmine.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-Carmine") + .Description("Creates HtmlDxDataGrid demo report for carmine theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Carmine)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-carmine.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-contrast.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-contrast.cake new file mode 100644 index 000000000..aa8fdbb8c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-contrast.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-Contrast") + .Description("Creates HtmlDxDataGrid demo report for contrast theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Contrast)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-contrast.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-contrastcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-contrastcompact.cake new file mode 100644 index 000000000..d1df8fe6a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-contrastcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-ContrastCompact") + .Description("Creates HtmlDxDataGrid demo report for contrast compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.ContrastCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-contrastcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-dark.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-dark.cake new file mode 100644 index 000000000..472143982 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-dark.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-Dark") + .Description("Creates HtmlDxDataGrid demo report for dark theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Dark)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-dark.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkcompact.cake new file mode 100644 index 000000000..8be604125 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-DarkCompact") + .Description("Creates HtmlDxDataGrid demo report for dark compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.DarkCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-darkcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkmoon.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkmoon.cake new file mode 100644 index 000000000..e8f2d38ba --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkmoon.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-DarkMoon") + .Description("Creates HtmlDxDataGrid demo report for dark moon theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.DarkMoon)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-darkmoon.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkviolet.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkviolet.cake new file mode 100644 index 000000000..7bce0e883 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-darkviolet.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-DarkViolet") + .Description("Creates HtmlDxDataGrid demo report for dark violet theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.DarkViolet)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-darkviolet.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-greenmist.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-greenmist.cake new file mode 100644 index 000000000..a1abacc04 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-greenmist.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-GreenMist") + .Description("Creates HtmlDxDataGrid demo report for green mist theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.GreenMist)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-greenmist.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-light.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-light.cake new file mode 100644 index 000000000..660985eb7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-light.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-Light") + .Description("Creates HtmlDxDataGrid demo report for light theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.Light)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-light.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-lightcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-lightcompact.cake new file mode 100644 index 000000000..a51cde469 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-lightcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-LightCompact") + .Description("Creates HtmlDxDataGrid demo report for light compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.LightCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-lightcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluedark.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluedark.cake new file mode 100644 index 000000000..e8f4ada56 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluedark.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueDark") + .Description("Creates HtmlDxDataGrid demo report for Material Blue Dark theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueDark)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluedark.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluedarkcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluedarkcompact.cake new file mode 100644 index 000000000..f06f451bc --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluedarkcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueDarkCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Blue Dark Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueDarkCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluedarkcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluelight.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluelight.cake new file mode 100644 index 000000000..097b3032b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluelight.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueLight") + .Description("Creates HtmlDxDataGrid demo report for Material Blue Light theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLight)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluelight.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluelightcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluelightcompact.cake new file mode 100644 index 000000000..baa24d081 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialbluelightcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueLightCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Blue Light Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialBlueLightCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialbluelightcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimedark.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimedark.cake new file mode 100644 index 000000000..d7402062f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimedark.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeDark") + .Description("Creates HtmlDxDataGrid demo report for Material Lime Dark theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeDark)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimedark.html")); +}); diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimedarkcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimedarkcompact.cake new file mode 100644 index 000000000..88f65d345 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimedarkcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeDarkCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Lime Dark Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeDarkCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimedarkcompact.html")); +}); diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimelight.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimelight.cake new file mode 100644 index 000000000..a6d9a514f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimelight.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeLight") + .Description("Creates HtmlDxDataGrid demo report for Material Lime Light theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeLight)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimelight.html")); +}); diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimelightcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimelightcompact.cake new file mode 100644 index 000000000..fc250d65d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materiallimelightcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeLightCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Lime Light Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialLimeLightCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materiallimelightcompact.html")); +}); diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangedark.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangedark.cake new file mode 100644 index 000000000..c1a441925 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangedark.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeDark") + .Description("Creates HtmlDxDataGrid demo report for Material Orange Dark theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeDark)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangedark.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangedarkcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangedarkcompact.cake new file mode 100644 index 000000000..86f71f5db --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangedarkcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeDarkCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Orange Dark Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeDarkCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangedarkcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangelight.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangelight.cake new file mode 100644 index 000000000..1de110f70 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangelight.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeLight") + .Description("Creates HtmlDxDataGrid demo report for Material Orange Light theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeLight)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangelight.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangelightcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangelightcompact.cake new file mode 100644 index 000000000..38655e802 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialorangelightcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeLightCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Orange Light Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialOrangeLightCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialorangelightcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurpledark.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurpledark.cake new file mode 100644 index 000000000..c518d706e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurpledark.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleDark") + .Description("Creates HtmlDxDataGrid demo report for Material Purple Dark theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleDark)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurpledark.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurpledarkcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurpledarkcompact.cake new file mode 100644 index 000000000..3bebea285 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurpledarkcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleDarkCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Purple Dark Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleDarkCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurpledarkcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurplelight.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurplelight.cake new file mode 100644 index 000000000..f8d28ae4b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurplelight.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleLight") + .Description("Creates HtmlDxDataGrid demo report for Material Purple Light theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleLight)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurplelight.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurplelightcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurplelightcompact.cake new file mode 100644 index 000000000..2e97e84bd --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialpurplelightcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleLightCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Purple Light Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialPurpleLightCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialpurplelightcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialtealdark.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialtealdark.cake new file mode 100644 index 000000000..2c2751d04 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialtealdark.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealDark") + .Description("Creates HtmlDxDataGrid demo report for Material Teal Dark theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealDark)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialtealdark.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialtealdarkcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialtealdarkcompact.cake new file mode 100644 index 000000000..f61cd4210 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialtealdarkcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealDarkCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Teal Dark Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealDarkCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialtealdarkcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialteallight.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialteallight.cake new file mode 100644 index 000000000..9ff3e33ea --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialteallight.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealLight") + .Description("Creates HtmlDxDataGrid demo report for Material Teal Light theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealLight)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialteallight.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialteallightcompact.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialteallightcompact.cake new file mode 100644 index 000000000..eeded18c1 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-materialteallightcompact.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealLightCompact") + .Description("Creates HtmlDxDataGrid demo report for Material Teal Light Compact theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.MaterialTealLightCompact)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-materialteallightcompact.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-softblue.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-softblue.cake new file mode 100644 index 000000000..31ab492fd --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid-theme-softblue.cake @@ -0,0 +1,14 @@ +Task("Create-Reports-HtmlDxDataGrid-Theme-SoftBlue") + .Description("Creates HtmlDxDataGrid demo report for soft blue theme") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + GenericIssueReportFormatFromEmbeddedTemplate( + GenericIssueReportTemplate.HtmlDxDataGrid, + settings => settings + .WithOption(HtmlDxDataGridOption.Theme, DevExtremeTheme.SoftBlue)), + data.RepoRootFolder, + data.TemplateGalleryFolder.CombineWithFilePath("htmldxdatagrid-demo-theme-softblue.html")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid.cake new file mode 100644 index 000000000..7ecc7c508 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports-htmldxdatagrid.cake @@ -0,0 +1,95 @@ +#load create-reports-htmldxdatagrid-default.cake +#load create-reports-htmldxdatagrid-theme-light.cake +#load create-reports-htmldxdatagrid-theme-dark.cake +#load create-reports-htmldxdatagrid-theme-contrast.cake +#load create-reports-htmldxdatagrid-theme-carmine.cake +#load create-reports-htmldxdatagrid-theme-darkmoon.cake +#load create-reports-htmldxdatagrid-theme-softblue.cake +#load create-reports-htmldxdatagrid-theme-darkviolet.cake +#load create-reports-htmldxdatagrid-theme-greenmist.cake +#load create-reports-htmldxdatagrid-theme-lightcompact.cake +#load create-reports-htmldxdatagrid-theme-darkcompact.cake +#load create-reports-htmldxdatagrid-theme-contrastcompact.cake +#load create-reports-htmldxdatagrid-theme-materialbluelight.cake +#load create-reports-htmldxdatagrid-theme-materiallimelight.cake +#load create-reports-htmldxdatagrid-theme-materialorangelight.cake +#load create-reports-htmldxdatagrid-theme-materialpurplelight.cake +#load create-reports-htmldxdatagrid-theme-materialteallight.cake +#load create-reports-htmldxdatagrid-theme-materialbluedark.cake +#load create-reports-htmldxdatagrid-theme-materiallimedark.cake +#load create-reports-htmldxdatagrid-theme-materialorangedark.cake +#load create-reports-htmldxdatagrid-theme-materialpurpledark.cake +#load create-reports-htmldxdatagrid-theme-materialtealdark.cake +#load create-reports-htmldxdatagrid-theme-materialbluelightcompact.cake +#load create-reports-htmldxdatagrid-theme-materiallimelightcompact.cake +#load create-reports-htmldxdatagrid-theme-materialorangelightcompact.cake +#load create-reports-htmldxdatagrid-theme-materialpurplelightcompact.cake +#load create-reports-htmldxdatagrid-theme-materialteallightcompact.cake +#load create-reports-htmldxdatagrid-theme-materialbluedarkcompact.cake +#load create-reports-htmldxdatagrid-theme-materiallimedarkcompact.cake +#load create-reports-htmldxdatagrid-theme-materialorangedarkcompact.cake +#load create-reports-htmldxdatagrid-theme-materialpurpledarkcompact.cake +#load create-reports-htmldxdatagrid-theme-materialtealdarkcompact.cake +#load create-reports-htmldxdatagrid-hide-columns.cake +#load create-reports-htmldxdatagrid-additional-columns.cake +#load create-reports-htmldxdatagrid-sorting.cake +#load create-reports-htmldxdatagrid-grouping.cake +#load create-reports-htmldxdatagrid-disable-grouping.cake +#load create-reports-htmldxdatagrid-change-title.cake +#load create-reports-htmldxdatagrid-disable-header.cake +#load create-reports-htmldxdatagrid-disable-filtering.cake +#load create-reports-htmldxdatagrid-disable-searching.cake +#load create-reports-htmldxdatagrid-custom-script-location.cake +#load create-reports-htmldxdatagrid-enable-exporting.cake +#load create-reports-htmldxdatagrid-exportformat-pdf.cake +#load create-reports-htmldxdatagrid-exportformat-xlsx.cake +#load create-reports-htmldxdatagrid-custom-export-filename.cake + +Task("Create-Reports-HtmlDxDataGrid") + .Description("Creates HtmlDxDataGrid demo reports") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Default") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-Light") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-Dark") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-Contrast") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-Carmine") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-DarkMoon") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-SoftBlue") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-DarkViolet") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-GreenMist") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-LightCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-DarkCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-ContrastCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueLight") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeLight") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeLight") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleLight") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealLight") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueDark") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeDark") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeDark") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleDark") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealDark") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueLightCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeLightCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeLightCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleLightCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealLightCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialBlueDarkCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialLimeDarkCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialOrangeDarkCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialPurpleDarkCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Theme-MaterialTealDarkCompact") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Hide-Columns") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Additional-Columns") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Sorting") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Grouping") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Disable-Grouping") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Change-Title") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Disable-Header") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Disable-Filtering") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Disable-Searching") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Custom-Script-Location") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Enable-Exporting") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-ExportFormat-Xlsx") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-ExportFormat-Pdf") + .IsDependentOn("Create-Reports-HtmlDxDataGrid-Custom-Export-Filename"); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports.cake b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports.cake new file mode 100644 index 000000000..cef49e03c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/build/create-reports/create-reports.cake @@ -0,0 +1,9 @@ +#load create-reports-htmldiagnostic.cake +#load create-reports-htmldatatable.cake +#load create-reports-htmldxdatagrid.cake + +Task("Create-Reports") + .Description("Creates all demo reports") + .IsDependentOn("Create-Reports-HtmlDiagnostic") + .IsDependentOn("Create-Reports-HtmlDataTable") + .IsDependentOn("Create-Reports-HtmlDxDataGrid"); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/docs/index.md b/tests/Cake.Issues.Reporting.Generic/script-runner/docs/index.md new file mode 100644 index 000000000..68eae7083 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/docs/index.md @@ -0,0 +1,7 @@ +# foo +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum dictum mauris, sed feugiat nibh rutrum eget. Fusce sed purus nec sem faucibus semper sed id est. Cras vestibulum leo nec ipsum posuere eleifend. Nullam iaculis quam in sapien efficitur consequat. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vivamus pulvinar bibendum sapien ac ultrices. Sed imperdiet mi non felis imperdiet, at interdum ante volutpat. Pellentesque eu cursus dolor, non iaculis ipsum. Quisque in tortor viverra, sodales nibh vitae, vehicula urna. Integer dolor mauris, condimentum ac accumsan quis, placerat eget tellus. Duis volutpat interdum nisi, vel efficitur nisl viverra vitae. Maecenas eget lacus vel lacus congue lobortis. Etiam ornare dictum nulla nec commodo. + +# bar +``` +Praesent euismod est vel quam volutpat ultrices. Cras luctus lorem quis nibh tincidunt, a auctor velit fermentum. Cras et nisl neque. Sed mi lorem, efficitur et purus eu, vehicula ornare felis. Aliquam sagittis ultricies sem, nec dignissim erat porta at. Suspendisse in justo lacus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque ornare neque porttitor tortor auctor lobortis posuere id dui. Phasellus et felis a nibh viverra cursus ut blandit ante. Suspendisse lacus tortor, pharetra non pulvinar vulputate, semper sed augue. Aenean feugiat finibus quam quis iaculis. Maecenas ac quam quis risus scelerisque rhoncus. Donec eget aliquam metus. Nam feugiat sem dui, quis consectetur lorem lobortis in. Maecenas eu bibendum sapien. +``` \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/global.json b/tests/Cake.Issues.Reporting.Generic/script-runner/global.json new file mode 100644 index 000000000..198c2bcb2 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.420", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/nuget.config b/tests/Cake.Issues.Reporting.Generic/script-runner/nuget.config new file mode 100644 index 000000000..62768c3d3 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1.sln b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..4539075f9 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.3.2 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/packages.config b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/packages.config new file mode 100644 index 000000000..719f545c7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/src/ClassLibrary1/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Generic/script-runner/tools/packages.config b/tests/Cake.Issues.Reporting.Generic/script-runner/tools/packages.config new file mode 100644 index 000000000..53cd3f875 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Generic/script-runner/tools/packages.config @@ -0,0 +1,4 @@ + + + + diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/.gitignore b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/.gitignore new file mode 100644 index 000000000..03f0fc267 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/.gitignore @@ -0,0 +1,348 @@ +### Project specific ### + +output/ + +# Created by https://www.gitignore.io/api/cake,visualstudio + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +*.pubxml.user + + +# End of https://www.gitignore.io/api/cake,visualstudio diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build.ps1 b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build.ps1 new file mode 100644 index 000000000..0ea12922b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build.ps1 @@ -0,0 +1,13 @@ +$ADDIN_PACKAGE_PATH = "packages/cake.isses.reprting.sarif" +if (Test-Path $ADDIN_PACKAGE_PATH) +{ + Write-Host "Cleaning up cached version of $ADDIN_PACKAGE_PATH..." + Remove-Item $ADDIN_PACKAGE_PATH -Recurse; +} +else +{ + Write-Host "$ADDIN_PACKAGE_PATH not cached..." +} + +dotnet run --project build/Build.csproj -- $args +exit $LASTEXITCODE; \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build.sh b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build.sh new file mode 100644 index 000000000..8a1fd4ab5 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build.sh @@ -0,0 +1,10 @@ +$ADDIN_PACKAGE_PATH = "packages/cake.issues.reporting.sarif" +if [ -d "$ADDIN_PACKAGE_PATH" ] +then + echo "Cleaning up cached version of $ADDIN_PACKAGE_PATH..." + rm -Rf $ADDIN_PACKAGE_PATH +else + echo "$ADDIN_PACKAGE_PATH not cached..." +fi + +dotnet run --project ./build/Build.csproj -- "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/Build.csproj b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/Build.csproj new file mode 100644 index 000000000..51dc84692 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/Build.csproj @@ -0,0 +1,13 @@ + + + Exe + net6.0 + $(MSBuildProjectDirectory) + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/Program.cs b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/Program.cs new file mode 100644 index 000000000..eff6a91ee --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/Program.cs @@ -0,0 +1,79 @@ +using Cake.Common.IO; +using Cake.Core; +using Cake.Core.IO; +using Cake.Frosting; +using Cake.Issues; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Sarif; +using System.Collections.Generic; + +public static class Program +{ + public static int Main(string[] args) + { + return new CakeHost() + .UseContext() + .Run(args); + } +} + +public class BuildContext : FrostingContext +{ + public DirectoryPath RepoRootFolder { get; } + public List Issues { get; } + + public BuildContext(ICakeContext context) + : base(context) + { + this.RepoRootFolder = context.MakeAbsolute(context.Directory("./../..")); + this.Issues = new List(); + } +} + +[TaskName("Create-CustomIssues")] +public class CreateCustomIssuesTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.Issues.Add( + context.NewIssue( + "Something went wrong", + "MyCakeScript", + "My Cake Script") + .WithMessageInHtmlFormat("Something went wrong") + .WithMessageInMarkdownFormat("Something went **wrong**") + .InFile("myfile.txt", 42) + .WithPriority(IssuePriority.Warning) + .Create() + ); + } +} + +[TaskName("Analyze")] +[IsDependentOn(typeof(CreateCustomIssuesTask))] +public class AnalyzeTask : FrostingTask +{ +} + +[TaskName("Create-Report")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReport : FrostingTask +{ + public override void Run(BuildContext context) + { + var outputFolder = context.RepoRootFolder.Combine("output"); + context.EnsureDirectoryExists(outputFolder); + + context.CreateIssueReport( + context.Issues, + context.SarifIssueReportFormat(), + context.RepoRootFolder, + outputFolder.CombineWithFilePath("issues.sarif")); + } +} + +[TaskName("Default")] +[IsDependentOn(typeof(CreateReport))] +public class DefaultTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/nuget.config b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/nuget.config new file mode 100644 index 000000000..32bdc0f18 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/build/nuget.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/global.json b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/global.json new file mode 100644 index 000000000..c31f98b70 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1.sln b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..9ec4dd90e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.0.0 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/packages.config b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/packages.config new file mode 100644 index 000000000..719f545c7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net6/src/ClassLibrary1/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/.gitignore b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/.gitignore new file mode 100644 index 000000000..03f0fc267 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/.gitignore @@ -0,0 +1,348 @@ +### Project specific ### + +output/ + +# Created by https://www.gitignore.io/api/cake,visualstudio + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +*.pubxml.user + + +# End of https://www.gitignore.io/api/cake,visualstudio diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build.ps1 b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build.ps1 new file mode 100644 index 000000000..0ea12922b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build.ps1 @@ -0,0 +1,13 @@ +$ADDIN_PACKAGE_PATH = "packages/cake.isses.reprting.sarif" +if (Test-Path $ADDIN_PACKAGE_PATH) +{ + Write-Host "Cleaning up cached version of $ADDIN_PACKAGE_PATH..." + Remove-Item $ADDIN_PACKAGE_PATH -Recurse; +} +else +{ + Write-Host "$ADDIN_PACKAGE_PATH not cached..." +} + +dotnet run --project build/Build.csproj -- $args +exit $LASTEXITCODE; \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build.sh b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build.sh new file mode 100644 index 000000000..8a1fd4ab5 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build.sh @@ -0,0 +1,10 @@ +$ADDIN_PACKAGE_PATH = "packages/cake.issues.reporting.sarif" +if [ -d "$ADDIN_PACKAGE_PATH" ] +then + echo "Cleaning up cached version of $ADDIN_PACKAGE_PATH..." + rm -Rf $ADDIN_PACKAGE_PATH +else + echo "$ADDIN_PACKAGE_PATH not cached..." +fi + +dotnet run --project ./build/Build.csproj -- "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/Build.csproj b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/Build.csproj new file mode 100644 index 000000000..5f18dafe1 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/Build.csproj @@ -0,0 +1,13 @@ + + + Exe + net7.0 + $(MSBuildProjectDirectory) + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/Program.cs b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/Program.cs new file mode 100644 index 000000000..eff6a91ee --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/Program.cs @@ -0,0 +1,79 @@ +using Cake.Common.IO; +using Cake.Core; +using Cake.Core.IO; +using Cake.Frosting; +using Cake.Issues; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Sarif; +using System.Collections.Generic; + +public static class Program +{ + public static int Main(string[] args) + { + return new CakeHost() + .UseContext() + .Run(args); + } +} + +public class BuildContext : FrostingContext +{ + public DirectoryPath RepoRootFolder { get; } + public List Issues { get; } + + public BuildContext(ICakeContext context) + : base(context) + { + this.RepoRootFolder = context.MakeAbsolute(context.Directory("./../..")); + this.Issues = new List(); + } +} + +[TaskName("Create-CustomIssues")] +public class CreateCustomIssuesTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.Issues.Add( + context.NewIssue( + "Something went wrong", + "MyCakeScript", + "My Cake Script") + .WithMessageInHtmlFormat("Something went wrong") + .WithMessageInMarkdownFormat("Something went **wrong**") + .InFile("myfile.txt", 42) + .WithPriority(IssuePriority.Warning) + .Create() + ); + } +} + +[TaskName("Analyze")] +[IsDependentOn(typeof(CreateCustomIssuesTask))] +public class AnalyzeTask : FrostingTask +{ +} + +[TaskName("Create-Report")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReport : FrostingTask +{ + public override void Run(BuildContext context) + { + var outputFolder = context.RepoRootFolder.Combine("output"); + context.EnsureDirectoryExists(outputFolder); + + context.CreateIssueReport( + context.Issues, + context.SarifIssueReportFormat(), + context.RepoRootFolder, + outputFolder.CombineWithFilePath("issues.sarif")); + } +} + +[TaskName("Default")] +[IsDependentOn(typeof(CreateReport))] +public class DefaultTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/nuget.config b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/nuget.config new file mode 100644 index 000000000..32bdc0f18 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/build/nuget.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/global.json b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/global.json new file mode 100644 index 000000000..e9812526d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "7.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1.sln b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..9ec4dd90e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.0.0 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/packages.config b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/packages.config new file mode 100644 index 000000000..719f545c7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net7/src/ClassLibrary1/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/.gitignore b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/.gitignore new file mode 100644 index 000000000..03f0fc267 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/.gitignore @@ -0,0 +1,348 @@ +### Project specific ### + +output/ + +# Created by https://www.gitignore.io/api/cake,visualstudio + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +*.pubxml.user + + +# End of https://www.gitignore.io/api/cake,visualstudio diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build.ps1 b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build.ps1 new file mode 100644 index 000000000..0ea12922b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build.ps1 @@ -0,0 +1,13 @@ +$ADDIN_PACKAGE_PATH = "packages/cake.isses.reprting.sarif" +if (Test-Path $ADDIN_PACKAGE_PATH) +{ + Write-Host "Cleaning up cached version of $ADDIN_PACKAGE_PATH..." + Remove-Item $ADDIN_PACKAGE_PATH -Recurse; +} +else +{ + Write-Host "$ADDIN_PACKAGE_PATH not cached..." +} + +dotnet run --project build/Build.csproj -- $args +exit $LASTEXITCODE; \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build.sh b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build.sh new file mode 100644 index 000000000..8a1fd4ab5 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build.sh @@ -0,0 +1,10 @@ +$ADDIN_PACKAGE_PATH = "packages/cake.issues.reporting.sarif" +if [ -d "$ADDIN_PACKAGE_PATH" ] +then + echo "Cleaning up cached version of $ADDIN_PACKAGE_PATH..." + rm -Rf $ADDIN_PACKAGE_PATH +else + echo "$ADDIN_PACKAGE_PATH not cached..." +fi + +dotnet run --project ./build/Build.csproj -- "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/Build.csproj b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/Build.csproj new file mode 100644 index 000000000..7cea6ca44 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/Build.csproj @@ -0,0 +1,13 @@ + + + Exe + net8.0 + $(MSBuildProjectDirectory) + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/Program.cs b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/Program.cs new file mode 100644 index 000000000..eff6a91ee --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/Program.cs @@ -0,0 +1,79 @@ +using Cake.Common.IO; +using Cake.Core; +using Cake.Core.IO; +using Cake.Frosting; +using Cake.Issues; +using Cake.Issues.Reporting; +using Cake.Issues.Reporting.Sarif; +using System.Collections.Generic; + +public static class Program +{ + public static int Main(string[] args) + { + return new CakeHost() + .UseContext() + .Run(args); + } +} + +public class BuildContext : FrostingContext +{ + public DirectoryPath RepoRootFolder { get; } + public List Issues { get; } + + public BuildContext(ICakeContext context) + : base(context) + { + this.RepoRootFolder = context.MakeAbsolute(context.Directory("./../..")); + this.Issues = new List(); + } +} + +[TaskName("Create-CustomIssues")] +public class CreateCustomIssuesTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.Issues.Add( + context.NewIssue( + "Something went wrong", + "MyCakeScript", + "My Cake Script") + .WithMessageInHtmlFormat("Something went wrong") + .WithMessageInMarkdownFormat("Something went **wrong**") + .InFile("myfile.txt", 42) + .WithPriority(IssuePriority.Warning) + .Create() + ); + } +} + +[TaskName("Analyze")] +[IsDependentOn(typeof(CreateCustomIssuesTask))] +public class AnalyzeTask : FrostingTask +{ +} + +[TaskName("Create-Report")] +[IsDependentOn(typeof(AnalyzeTask))] +public class CreateReport : FrostingTask +{ + public override void Run(BuildContext context) + { + var outputFolder = context.RepoRootFolder.Combine("output"); + context.EnsureDirectoryExists(outputFolder); + + context.CreateIssueReport( + context.Issues, + context.SarifIssueReportFormat(), + context.RepoRootFolder, + outputFolder.CombineWithFilePath("issues.sarif")); + } +} + +[TaskName("Default")] +[IsDependentOn(typeof(CreateReport))] +public class DefaultTask : FrostingTask +{ +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/nuget.config b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/nuget.config new file mode 100644 index 000000000..32bdc0f18 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/build/nuget.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/global.json b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/global.json new file mode 100644 index 000000000..3660ff882 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "8.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1.sln b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..9ec4dd90e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.0.0 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/packages.config b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/packages.config new file mode 100644 index 000000000..719f545c7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/frosting/net8/src/ClassLibrary1/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/.config/dotnet-tools.json b/tests/Cake.Issues.Reporting.Sarif/script-runner/.config/dotnet-tools.json new file mode 100644 index 000000000..da200cdae --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "4.0.0", + "commands": [ + "dotnet-cake" + ] + } + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/.gitignore b/tests/Cake.Issues.Reporting.Sarif/script-runner/.gitignore new file mode 100644 index 000000000..03f0fc267 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/.gitignore @@ -0,0 +1,348 @@ +### Project specific ### + +output/ + +# Created by https://www.gitignore.io/api/cake,visualstudio + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +*.pubxml.user + + +# End of https://www.gitignore.io/api/cake,visualstudio diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/.markdownlint.json b/tests/Cake.Issues.Reporting.Sarif/script-runner/.markdownlint.json new file mode 100644 index 000000000..5bcc68ac6 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/.markdownlint.json @@ -0,0 +1,10 @@ +{ + "default": true, + "MD003": { "style": "atx" }, + "MD004": { "style": "asterisk" }, + "MD007": { "indent": 4 }, + "MD009": { "br_spaces": 2 }, + "MD013": { "line_length": 100, "tables": false, "code_blocks": false }, + "MD029": { "style": "ordered" }, + "MD035": { "style": "----------------------------------------------------------------------------------------------------" } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build.cake new file mode 100644 index 000000000..3f5bdaf3c --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build.cake @@ -0,0 +1,44 @@ +#addin "Cake.Markdownlint" +#addin "Cake.Issues&prerelease" +#addin "Cake.Issues.MsBuild&prerelease" +#addin "Cake.Issues.Markdownlint&prerelease" +#addin "Cake.Issues.InspectCode&prerelease" +#addin "Cake.Issues.Reporting&prerelease" +#addin "Cake.Issues.Reporting.Sarif&prerelease" + +#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2021.2.2" + +#load build/build/build.cake +#load build/analyze/analyze.cake +#load build/create-reports/create-reports.cake + +var target = Argument("target", "Default"); + +public class BuildData +{ + public DirectoryPath RepoRootFolder { get; } + public DirectoryPath SourceFolder { get; } + public DirectoryPath DocsFolder { get; } + public DirectoryPath OutputFolder { get; } + public List Issues { get; } + + public BuildData(ICakeContext context) + { + this.RepoRootFolder = context.MakeAbsolute(context.Directory("./")); + this.SourceFolder = this.RepoRootFolder.Combine("src"); + this.DocsFolder = this.RepoRootFolder.Combine("docs"); + this.OutputFolder = this.RepoRootFolder.Combine("output"); + + this.Issues = new List(); + } +} + +Setup(setupContext => +{ + return new BuildData(setupContext); +}); + +Task("Default") + .IsDependentOn("Create-Reports"); + +RunTarget(target); diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build.ps1 b/tests/Cake.Issues.Reporting.Sarif/script-runner/build.ps1 new file mode 100644 index 000000000..fe6027689 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build.ps1 @@ -0,0 +1,15 @@ +$ErrorActionPreference = 'Stop' + +$SCRIPT_NAME = "build.cake" + +Write-Host "Restoring .NET Core tools" +dotnet tool restore +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +Write-Host "Running Build" +dotnet cake $SCRIPT_NAME @args +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build.sh b/tests/Cake.Issues.Reporting.Sarif/script-runner/build.sh new file mode 100644 index 000000000..921a3241b --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash +SCRIPT_NAME="build.cake" + +echo "Restoring .NET Core tools" +dotnet tool restore + +echo "Bootstrapping Cake" +dotnet cake $SCRIPT_NAME --bootstrap + +echo "Running Build" +dotnet cake $SCRIPT_NAME "$@" \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/analyze.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/analyze.cake new file mode 100644 index 000000000..7ee43fb8f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/analyze.cake @@ -0,0 +1,9 @@ +#load inspectcode.cake +#load markdownlint.cake +#load custom-issue.cake + +Task("Analyze") + .IsDependentOn("Build") + .IsDependentOn("Run-InspectCode") + .IsDependentOn("Lint-Documentation") + .IsDependentOn("Create-CustomIssues"); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/custom-issue.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/custom-issue.cake new file mode 100644 index 000000000..de300b98f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/custom-issue.cake @@ -0,0 +1,16 @@ +Task("Create-CustomIssues") + .Description("Creates additional issues in the build script") + .Does(data => +{ + data.Issues.Add( + NewIssue( + "Something went wrong", + "MyCakeScript", + "My Cake Script") + .WithMessageInHtmlFormat("Something went wrong") + .WithMessageInMarkdownFormat("Something went **wrong**") + .InFile("myfile.txt", 42) + .WithPriority(IssuePriority.Warning) + .Create() + ); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/inspectcode.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/inspectcode.cake new file mode 100644 index 000000000..665f72712 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/inspectcode.cake @@ -0,0 +1,31 @@ +Task("Run-InspectCode") + .Description("Runs JetBrains InspectCode analysis") + .WithCriteria((context) => context.IsRunningOnWindows(), "InspectCode is only supported on Windows.") + .Does(data => +{ + var inspectCodeLogFilePath = + data.OutputFolder.CombineWithFilePath("inspectCode.log"); + + // Run InspectCode + var settings = new InspectCodeSettings() { + OutputFile = inspectCodeLogFilePath + }; + + InspectCode(data.SourceFolder.CombineWithFilePath("ClassLibrary1.sln"), settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Sarif"), + "develop", + "tests" + ) + }; + + data.Issues.AddRange( + ReadIssues( + InspectCodeIssuesFromFilePath(inspectCodeLogFilePath), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/markdownlint.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/markdownlint.cake new file mode 100644 index 000000000..f2afbd89e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/analyze/markdownlint.cake @@ -0,0 +1,69 @@ +Task("Lint-Documentation") + .IsDependentOn("Lint-TestDocumentation") + .IsDependentOn("Lint-AddinDocumentation"); + +Task("Lint-TestDocumentation") + .Description("Runs Markdownint on test documentation") + .Does(data => +{ + var markdownLintLogFilePath = data.OutputFolder.CombineWithFilePath("markdownlint-tests.log"); + + // Run markdownlint + var settings = + MarkdownlintNodeJsRunnerSettings.ForDirectory(data.DocsFolder); + settings.OutputFile = markdownLintLogFilePath; + settings.ThrowOnIssue = false; + RunMarkdownlintNodeJs(settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + Run = "Demos documentation", + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Sarif"), + "develop", + "tests" + ) + }; + + data.Issues.AddRange( + ReadIssues( + MarkdownlintIssuesFromFilePath( + markdownLintLogFilePath, + MarkdownlintCliLogFileFormat), + readIssuesSettings)); +}); + +Task("Lint-AddinDocumentation") + .Description("Runs Markdownint on addin documentation") + .Does(data => +{ + var markdownLintLogFilePath = data.OutputFolder.CombineWithFilePath("markdownlint-addin.log"); + + // Run markdownlint + var settings = + MarkdownlintNodeJsRunnerSettings.ForDirectory(data.RepoRootFolder.Combine("../../../docs")); + settings.OutputFile = markdownLintLogFilePath; + settings.ThrowOnIssue = false; + RunMarkdownlintNodeJs(settings); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + Run = "Addin documentation", + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Sarif"), + "develop", + "docs" + ) + }; + + data.Issues.AddRange( + ReadIssues( + MarkdownlintIssuesFromFilePath( + markdownLintLogFilePath, + MarkdownlintCliLogFileFormat), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build/build/build.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/build/build.cake new file mode 100644 index 000000000..49ed46c04 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/build/build.cake @@ -0,0 +1,43 @@ +Task("Build") + .Description("Builds the solution") + .Does(data => +{ + var solutionFile = data.SourceFolder.CombineWithFilePath("ClassLibrary1.sln"); + var msBuildLogFilePath = data.OutputFolder.CombineWithFilePath("msbuild.binlog"); + + DotNetRestore(solutionFile.FullPath); + + var settings = + new DotNetMSBuildSettings() + .WithTarget("Rebuild") + .WithLogger( + "BinaryLogger," + Context.Tools.Resolve("Cake.Issues.MsBuild*/**/StructuredLogger.dll"), + "", + msBuildLogFilePath.FullPath + ); + + DotNetBuild( + solutionFile.FullPath, + new DotNetBuildSettings + { + MSBuildSettings = settings + }); + + // Read issues + var readIssuesSettings = new ReadIssuesSettings(data.RepoRootFolder) + { + FileLinkSettings = + IssueFileLinkSettingsForGitHubBranch( + new System.Uri("https://github.com/cake-contrib/Cake.Issues.Reporting.Sarif"), + "develop", + "tests" + ) + }; + + data.Issues.AddRange( + ReadIssues( + MsBuildIssuesFromFilePath( + msBuildLogFilePath, + MsBuildBinaryLogFileFormat), + readIssuesSettings)); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/build/create-reports/create-reports.cake b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/create-reports/create-reports.cake new file mode 100644 index 000000000..4e1cd108f --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/build/create-reports/create-reports.cake @@ -0,0 +1,15 @@ +Task("Create-Reports") + .Description("Creates all demo reports") + .IsDependentOn("Create-Reports-Default"); + +Task("Create-Reports-Default") + .Description("Creates default SARIF report") + .IsDependentOn("Analyze") + .Does(data => +{ + CreateIssueReport( + data.Issues, + SarifIssueReportFormat(), + data.RepoRootFolder, + data.OutputFolder.CombineWithFilePath("report.sarif")); +}); \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/docs/index.md b/tests/Cake.Issues.Reporting.Sarif/script-runner/docs/index.md new file mode 100644 index 000000000..68eae7083 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/docs/index.md @@ -0,0 +1,7 @@ +# foo +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum dictum mauris, sed feugiat nibh rutrum eget. Fusce sed purus nec sem faucibus semper sed id est. Cras vestibulum leo nec ipsum posuere eleifend. Nullam iaculis quam in sapien efficitur consequat. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vivamus pulvinar bibendum sapien ac ultrices. Sed imperdiet mi non felis imperdiet, at interdum ante volutpat. Pellentesque eu cursus dolor, non iaculis ipsum. Quisque in tortor viverra, sodales nibh vitae, vehicula urna. Integer dolor mauris, condimentum ac accumsan quis, placerat eget tellus. Duis volutpat interdum nisi, vel efficitur nisl viverra vitae. Maecenas eget lacus vel lacus congue lobortis. Etiam ornare dictum nulla nec commodo. + +# bar +``` +Praesent euismod est vel quam volutpat ultrices. Cras luctus lorem quis nibh tincidunt, a auctor velit fermentum. Cras et nisl neque. Sed mi lorem, efficitur et purus eu, vehicula ornare felis. Aliquam sagittis ultricies sem, nec dignissim erat porta at. Suspendisse in justo lacus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque ornare neque porttitor tortor auctor lobortis posuere id dui. Phasellus et felis a nibh viverra cursus ut blandit ante. Suspendisse lacus tortor, pharetra non pulvinar vulputate, semper sed augue. Aenean feugiat finibus quam quis iaculis. Maecenas ac quam quis risus scelerisque rhoncus. Donec eget aliquam metus. Nam feugiat sem dui, quis consectetur lorem lobortis in. Maecenas eu bibendum sapien. +``` \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/global.json b/tests/Cake.Issues.Reporting.Sarif/script-runner/global.json new file mode 100644 index 000000000..c31f98b70 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "allowPrerelease": true, + "version": "6.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/nuget.config b/tests/Cake.Issues.Reporting.Sarif/script-runner/nuget.config new file mode 100644 index 000000000..62768c3d3 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/nuget.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1.sln b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1.sln new file mode 100644 index 000000000..62df92e3d --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{9B73BB5B-06A3-46F3-9068-E3607A8217B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B73BB5B-06A3-46F3-9068-E3607A8217B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/Class1.cs b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/Class1.cs new file mode 100644 index 000000000..4ea00049a --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/Class1.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ClassLibrary1 +{ + public class Class1 + { + public void Foo() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + + public void Bar() + { + var foo = "foo"; + var bar = "bar"; + if (!string.IsNullOrEmpty(foo) && !string.IsNullOrEmpty(bar)) + { + var foobar = foo + bar; + } + } + } +} diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/ClassLibrary1.csproj b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/ClassLibrary1.csproj new file mode 100644 index 000000000..9ec4dd90e --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/ClassLibrary1.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + + + + all + 3.0.0 + + + all + 1.1.118 + + + + + + + \ No newline at end of file diff --git a/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/packages.config b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/packages.config new file mode 100644 index 000000000..719f545c7 --- /dev/null +++ b/tests/Cake.Issues.Reporting.Sarif/script-runner/src/ClassLibrary1/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file