diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml index deb55c84..d1b9dcb4 100644 --- a/.github/workflows/backend-ci.yml +++ b/.github/workflows/backend-ci.yml @@ -65,8 +65,11 @@ jobs: - name: dotnet restore run: dotnet restore --locked-mode + - name: dotnet tool restore + run: dotnet tool restore + - name: Build - id: npm-build + id: dotnet-build run: | dotnet build -c Release --no-restore --nologo -consoleLoggerParameters:NoSummary -verbosity:quiet 1>build.out 2>&1 || (exit 0) grep "): error " build.out > build.err || (exit 0) @@ -105,11 +108,67 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-build-results" - comment-content: ${{ steps.npm-build.outputs.result }} + comment-content: ${{ steps.dotnet-build.outputs.result }} + + - name: WebApi Tests + run: dotnet test ../../tests/backend/WebApi.Tests --no-restore --collect:"XPlat Code Coverage" --logger "trx;LogFileName=test-results.trx" /p:CollectCoverage=true /p:CoverletOutput="../../tests/backend/WebApi.Tests/TestResults/" /p:CoverletOutputFormat=cobertura + + - uses: dorny/test-reporter@v1 + with: + name: "WebApi Tests" + path: "tests/backend/WebApi.Tests/TestResults/test-results.trx" + reporter: dotnet-trx + fail-on-error: true + + - name: Generate report for all tests + id: reportgenerator + run: | + dotnet reportgenerator -reports:"../../tests/backend/**/TestResults/**/coverage.cobertura.xml" -targetdir:"../../tests/backend/CoverageReport" -reporttypes:"Html;Cobertura;MarkdownSummaryGithub;Badges" + cat ../../tests/backend/CoverageReport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY + echo "markdown<> $GITHUB_OUTPUT + cat ../../tests/backend/CoverageReport/SummaryGithub.md >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + # TODO: commit the badges for README.md + + - name: "Create or Update PR Comment" + uses: im-open/update-pr-comment@v1.2.2 + if: ${{ always() && github.event_name == 'pull_request' }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-reportgenerator" + comment-content: ${{ steps.reportgenerator.outputs.markdown }} + + - name: Code Coverage Report + uses: irongut/CodeCoverageSummary@v1.3.0 + with: + filename: "tests/backend/CoverageReport/Cobertura.xml" + badge: true + fail_below_min: false + format: markdown + hide_branch_rate: false + hide_complexity: true + indicators: true + output: both + thresholds: "60 80" + + - name: Create output variable + id: code-coverage-summary + run: | + cat ../../code-coverage-results.md >> $GITHUB_STEP_SUMMARY + echo "markdown<> $GITHUB_OUTPUT + cat ../../code-coverage-results.md >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: "Create or Update PR Comment" + uses: im-open/update-pr-comment@v1.2.2 + if: ${{ always() && github.event_name == 'pull_request' }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + comment-identifier: "${{ env.WORKFLOW_SHORT_NAME }}-CodeCoverageSummary" + comment-content: ${{ steps.code-coverage-summary.outputs.markdown }} - name: Inspect code uses: muno92/resharper_inspectcode@v1 - if: always() with: workingDirectory: ${{ env.BACKEND_SOLUTION_PATH }} solutionPath: Backend.sln diff --git a/.github/workflows/deploy-cd.yml b/.github/workflows/deploy-cd.yml index e31c46d6..595f242f 100644 --- a/.github/workflows/deploy-cd.yml +++ b/.github/workflows/deploy-cd.yml @@ -39,10 +39,10 @@ env: DOCKER_REGISTRY_SERVER: "crtest${{ inputs.deploy_target }}ne.azurecr.io" DOCKER_REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} DOCKER_REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} - ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }} - ARM_SUBSCRIPTION_ID: ${{ vars.ARM_SUBSCRIPTION_ID }} - ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }} - ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} + # ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }} + # ARM_SUBSCRIPTION_ID: ${{ vars.ARM_SUBSCRIPTION_ID }} + # ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }} + # ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} POWERAPPS_ENVIRONMENTURL: ${{ secrets.POWERAPPS_ENVIRONMENTURL }} POWERAPPS_APPID: ${{ secrets.POWERAPPS_APPID }} POWERAPPS_TENANTID: ${{ secrets.POWERAPPS_TENANTID }} diff --git a/.gitignore b/.gitignore index 5073cb63..51fca6ab 100644 --- a/.gitignore +++ b/.gitignore @@ -402,3 +402,6 @@ FodyWeavers.xsd # OS-specific files .DS_Store + +# Coverage report files +CoverageReport/ diff --git a/src/backend/.config/dotnet-tools.json b/src/backend/.config/dotnet-tools.json index 677ed3f7..d6b6f812 100644 --- a/src/backend/.config/dotnet-tools.json +++ b/src/backend/.config/dotnet-tools.json @@ -7,6 +7,12 @@ "commands": [ "dotnet-ef" ] + }, + "dotnet-reportgenerator-globaltool": { + "version": "5.2.4", + "commands": [ + "reportgenerator" + ] } } } \ No newline at end of file diff --git a/src/backend/Backend.sln b/src/backend/Backend.sln index 1d9c51cb..a887cd7c 100644 --- a/src/backend/Backend.sln +++ b/src/backend/Backend.sln @@ -3,7 +3,25 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34031.279 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "WebApi\WebApi.csproj", "{967AAD03-89D9-4352-BAF5-40CF10F28C35}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi", "WebApi\WebApi.csproj", "{967AAD03-89D9-4352-BAF5-40CF10F28C35}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi.Tests", "..\..\tests\backend\WebApi.Tests\WebApi.Tests.csproj", "{83C523DE-4F91-4C54-A4F0-5D24CCF251D0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9EBA80A2-4F3D-4EBC-AC53-3D4DE1719443}" + ProjectSection(SolutionItems) = preProject + ..\..\README.md = ..\..\README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B9B9AD30-0723-4C38-868E-5E9D9CB458CE}" + ProjectSection(SolutionItems) = preProject + ..\..\tests\backend\Directory.Build.props = ..\..\tests\backend\Directory.Build.props + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F9FCA971-68B4-4828-A6EC-1A16DDF1E983}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + global.json = global.json + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,10 +33,18 @@ Global {967AAD03-89D9-4352-BAF5-40CF10F28C35}.Debug|Any CPU.Build.0 = Debug|Any CPU {967AAD03-89D9-4352-BAF5-40CF10F28C35}.Release|Any CPU.ActiveCfg = Release|Any CPU {967AAD03-89D9-4352-BAF5-40CF10F28C35}.Release|Any CPU.Build.0 = Release|Any CPU + {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83C523DE-4F91-4C54-A4F0-5D24CCF251D0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B9B9AD30-0723-4C38-868E-5E9D9CB458CE} = {9EBA80A2-4F3D-4EBC-AC53-3D4DE1719443} + {F9FCA971-68B4-4828-A6EC-1A16DDF1E983} = {9EBA80A2-4F3D-4EBC-AC53-3D4DE1719443} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A57A04D2-2D56-4C4F-A03F-BC3E671898F8} EndGlobalSection diff --git a/tests/backend/Directory.Build.props b/tests/backend/Directory.Build.props new file mode 100644 index 00000000..9e48d722 --- /dev/null +++ b/tests/backend/Directory.Build.props @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/backend/WebApi.Tests/UnitTest1.cs b/tests/backend/WebApi.Tests/UnitTest1.cs new file mode 100644 index 00000000..f8816902 --- /dev/null +++ b/tests/backend/WebApi.Tests/UnitTest1.cs @@ -0,0 +1,15 @@ +namespace WebApi.Tests; + +public class Tests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } +} \ No newline at end of file diff --git a/tests/backend/WebApi.Tests/WebApi.Tests.csproj b/tests/backend/WebApi.Tests/WebApi.Tests.csproj new file mode 100644 index 00000000..0c3577b4 --- /dev/null +++ b/tests/backend/WebApi.Tests/WebApi.Tests.csproj @@ -0,0 +1,24 @@ + + + + false + true + + + + + + + + + + + + + + + + + + + diff --git a/tests/backend/WebApi.Tests/packages.lock.json b/tests/backend/WebApi.Tests/packages.lock.json new file mode 100644 index 00000000..21906507 --- /dev/null +++ b/tests/backend/WebApi.Tests/packages.lock.json @@ -0,0 +1,166 @@ +{ + "version": 1, + "dependencies": { + "net8.0": { + "coverlet.collector": { + "type": "Direct", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ==" + }, + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[17.8.0, )", + "resolved": "17.8.0", + "contentHash": "BmTYGbD/YuDHmApIENdoyN1jCk0Rj1fJB0+B/fVekyTdVidr91IlzhqzytiUgaEAzL1ZJcYCme0MeBMYvJVzvw==", + "dependencies": { + "Microsoft.CodeCoverage": "17.8.0", + "Microsoft.TestPlatform.TestHost": "17.8.0" + } + }, + "NUnit": { + "type": "Direct", + "requested": "[3.14.0, )", + "resolved": "3.14.0", + "contentHash": "R7iPwD7kbOaP3o2zldWJbWeMQAvDKD0uld27QvA3PAALl1unl7x0v2J7eGiJOYjimV/BuGT4VJmr45RjS7z4LA==", + "dependencies": { + "NETStandard.Library": "2.0.0" + } + }, + "NUnit.Analyzers": { + "type": "Direct", + "requested": "[3.9.0, )", + "resolved": "3.9.0", + "contentHash": "8bGAEljlBnzR+uU8oGQhTVKnbgBw1Mo71qjVkgzHdvtUkiB5XOIDyjAcS4KUo/j+F2Zv/xBUZRkCWXmejx4bfA==" + }, + "NUnit3TestAdapter": { + "type": "Direct", + "requested": "[4.5.0, )", + "resolved": "4.5.0", + "contentHash": "s8JpqTe9bI2f49Pfr3dFRfoVSuFQyraTj68c3XXjIS/MRGvvkLnrg6RLqnTjdShX+AdFUCCU/4Xex58AdUfs6A==" + }, + "Microsoft.AspNetCore.OpenApi": { + "type": "Transitive", + "resolved": "8.0.4", + "contentHash": "TFiXbP0tqRgJKcpiCSSp79q6QaiF8gqRhZgrU48FQajhVkiwHSp1O1b1hkYC4Ehl4clbk3pHwdfwN9mRtDAFbQ==", + "dependencies": { + "Microsoft.OpenApi": "1.4.3" + } + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "17.8.0", + "contentHash": "KC8SXWbGIdoFVdlxKk9WHccm0llm9HypcHMLUUFabRiTS3SO2fQXNZfdiF3qkEdTJhbRrxhdRxjL4jbtwPq4Ew==" + }, + "Microsoft.Extensions.ApiDescription.Server": { + "type": "Transitive", + "resolved": "6.0.5", + "contentHash": "Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.OpenApi": { + "type": "Transitive", + "resolved": "1.4.3", + "contentHash": "rURwggB+QZYcSVbDr7HSdhw/FELvMlriW10OeOzjPT7pstefMo7IThhtNtDudxbXhW+lj0NfX72Ka5EDsG8x6w==" + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "17.8.0", + "contentHash": "AYy6vlpGMfz5kOFq99L93RGbqftW/8eQTqjT9iGXW6s9MRP3UdtY8idJ8rJcjeSja8A18IhIro5YnH3uv1nz4g==", + "dependencies": { + "NuGet.Frameworks": "6.5.0", + "System.Reflection.Metadata": "1.6.0" + } + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "17.8.0", + "contentHash": "9ivcl/7SGRmOT0YYrHQGohWiT5YCpkmy/UEzldfVisLm6QxbLaK3FAJqZXI34rnRLmqqDCeMQxKINwmKwAPiDw==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "17.8.0", + "Newtonsoft.Json": "13.0.1" + } + }, + "Microsoft.VisualStudio.Azure.Containers.Tools.Targets": { + "type": "Transitive", + "resolved": "1.20.1", + "contentHash": "H4bIRdEOuyWBotgdPA5oCjJmUekWrtU5lOKnMAVaSNduZXHnqFZECsYbkm4vIOE4aeIO8TEYqfsZaJus1KknLQ==" + }, + "NETStandard.Library": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "7jnbRU+L08FXKMxqUflxEXtVymWvNOrS8yHgu9s6EM8Anr6T/wIX4nZ08j/u3Asz+tCufp3YVwFSEvFTPYmBPA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "6.5.0", + "contentHash": "QWINE2x3MbTODsWT1Gh71GaGb5icBz4chS8VYvTgsBnsi8esgN6wtHhydd7fvToWECYGq7T4cgBBDiKD/363fg==" + }, + "Swashbuckle.AspNetCore": { + "type": "Transitive", + "resolved": "6.5.0", + "contentHash": "FK05XokgjgwlCI6wCT+D4/abtQkL1X1/B9Oas6uIwHFmYrIO9WUD5aLC9IzMs9GnHfUXOtXZ2S43gN1mhs5+aA==", + "dependencies": { + "Microsoft.Extensions.ApiDescription.Server": "6.0.5", + "Swashbuckle.AspNetCore.Swagger": "6.5.0", + "Swashbuckle.AspNetCore.SwaggerGen": "6.5.0", + "Swashbuckle.AspNetCore.SwaggerUI": "6.5.0" + } + }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "Transitive", + "resolved": "6.5.0", + "contentHash": "MlysLblpiWftmqhMGaBEymkroFBlssFZzKr+7YHvvBrV5ymwAjdJ7bDBTTv5/qhaPZK6HoMu1ig3IwK2YtLTOg==" + }, + "Swashbuckle.AspNetCore.Swagger": { + "type": "Transitive", + "resolved": "6.5.0", + "contentHash": "XWmCmqyFmoItXKFsQSwQbEAsjDKcxlNf1l+/Ki42hcb6LjKL8m5Db69OTvz5vLonMSRntYO1XLqz0OP+n3vKnA==", + "dependencies": { + "Microsoft.OpenApi": "1.2.3" + } + }, + "Swashbuckle.AspNetCore.SwaggerGen": { + "type": "Transitive", + "resolved": "6.5.0", + "contentHash": "Y/qW8Qdg9OEs7V013tt+94OdPxbRdbhcEbw4NiwGvf4YBcfhL/y7qp/Mjv/cENsQ2L3NqJ2AOu94weBy/h4KvA==", + "dependencies": { + "Swashbuckle.AspNetCore.Swagger": "6.5.0" + } + }, + "Swashbuckle.AspNetCore.SwaggerUI": { + "type": "Transitive", + "resolved": "6.5.0", + "contentHash": "OvbvxX+wL8skxTBttcBsVxdh73Fag4xwqEU2edh4JMn7Ws/xJHnY/JB1e9RoCb6XpDxUF3hD9A0Z1lEUx40Pfw==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "1.6.0", + "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" + }, + "webapi": { + "type": "Project", + "dependencies": { + "Microsoft.AspNetCore.OpenApi": "[8.0.4, )", + "Microsoft.VisualStudio.Azure.Containers.Tools.Targets": "[1.20.1, )", + "Swashbuckle.AspNetCore": "[6.5.0, )", + "Swashbuckle.AspNetCore.ReDoc": "[6.5.0, )" + } + } + }, + "net8.0/linux-musl-x64": {}, + "net8.0/win-x64": {} + } +} \ No newline at end of file