diff --git a/.github/actions/build-test/action.yml b/.github/actions/build-test/action.yml new file mode 100644 index 0000000..33bbd58 --- /dev/null +++ b/.github/actions/build-test/action.yml @@ -0,0 +1,59 @@ +# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions +# https://doug.sh/posts/using-composite-actions-with-github-actions/ +# https://wallis.dev/blog/composite-github-actions + +name: "Build-Test" +description: "Build and test service" + +# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string) +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs +inputs: + project-path: + description: Project path + required: true + tests-path: + description: Test path + required: false + default: '' + reports-path: + description: Test report path + required: true + reports-output-path: + description: Test report output path + required: true + service-name: + description: Service name + required: true + # https://stackoverflow.com/questions/70098241/using-secrets-in-composite-actions-github + token: + description: A Github PAT + required: true + +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions +runs: + using: "composite" + steps: + + - name: Call Composite Action build + uses: ./.github/actions/build + if: success() + id: build-step + with: + project-path: ${{ inputs.project-path }} + service-name: ${{ inputs.service-name }} + + - name: Call Composite Action test + uses: ./.github/actions/test + if: ${{ success() && inputs.tests-path != ''}} + id: test-step + with: + tests-path: ${{ inputs.tests-path }} + # wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory + # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/ + # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not + reports-path: ${{ github.workspace }}/**/*.cobertura.xml + reports-output-path: ${{ github.workspace }}/output/test-results + service-name: ${{ inputs.service-name }} + token: ${{ inputs.token }} + no-restore: true diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml new file mode 100644 index 0000000..4429dd0 --- /dev/null +++ b/.github/actions/build/action.yml @@ -0,0 +1,55 @@ +# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions +# https://doug.sh/posts/using-composite-actions-with-github-actions/ +# https://wallis.dev/blog/composite-github-actions + +name: "Build" +description: "Build service" + +# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string) +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs +inputs: + project-path: + description: Project path + required: true + service-name: + description: Service name + required: true + +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions +runs: + using: "composite" + steps: + + # https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows + # https://devblogs.microsoft.com/dotnet/dotnet-loves-github-actions/ + # https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net#caching-dependencies + - name: Cache NuGet Packages + uses: actions/cache@v3 + if: success() + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-dotnet-nuget + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + + # https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools + - name: Restore .NET Tools + shell: bash + run: dotnet tool restore + + # Note: `Ubuntu` file and folder names are case sensitive, be aware about naming them in solution references. because `Windows` file and folder names as case-insensitive. + # prevent windows case-insensitive for our project with: git config core.ignorecase false; - https://stackoverflow.com/a/27139487/581476 + - name: Restore NuGet packages + shell: bash + if: success() + # restore root solution + run: dotnet restore + + - name: Build Service + shell: bash + if: ${{ success()}} + working-directory: ${{ inputs.project-path }} + run: | + dotnet build -c Release --no-restore diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml new file mode 100644 index 0000000..f218044 --- /dev/null +++ b/.github/actions/test/action.yml @@ -0,0 +1,85 @@ +# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions +# https://doug.sh/posts/using-composite-actions-with-github-actions/ +# https://wallis.dev/blog/composite-github-actions + +name: "Test" +description: "Test service" + +# Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables.(so they are just string) +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs +inputs: + tests-path: + description: Test path + required: true + reports-path: + description: Test report path + required: true + reports-output-path: + description: Test report output path + required: true + service-name: + description: Service name + required: true + # https://stackoverflow.com/questions/70098241/using-secrets-in-composite-actions-github + token: + description: A Github PAT + required: true + no-restore: + description: No restore nuget packages, but building tests because they don't build in the build composition action + default: 'true' + +# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-actions +runs: + using: "composite" + steps: + + # see here https://samlearnsazure.blog/2021/01/05/code-coverage-in-github-with-net-core/ + # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/ + # https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details + # https://josef.codes/dotnet-core-filter-out-specific-test-projects-when-running-dotnet-test/ + # https://learn.microsoft.com/en-us/dotnet/core/testing/selective-unit-tests?pivots=xunit + # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not + # https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md + # https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md#filters + - name: Tests + shell: bash + id: tests-step + working-directory: ${{ inputs.tests-path }} + # https://stackoverflow.com/questions/3779701/msbuild-error-msb1008-only-one-project-can-be-specified + # https://octopus.com/blog/githubactions-running-unit-tests + # we should not do 'no-build' here, because our tests not build in build phase (build composite action) and should build here + run: | + for file in $(find . -name "*.csproj" -type f); do + echo "Testing $file" + if [ ${{ inputs.no-restore }} == 'true' ]; then + echo "run tests in no-restore mode" + dotnet test "$file" -c Release --no-restore --logger "trx;LogFileName=test-results.trx" || true + else + echo "run tests in restore nuget mode" + dotnet test "$file" -c Release --logger "trx;LogFileName=test-results.trx" || true + fi + done + + # GitHub Api call permissions problem here + # https://github.com/dorny/test-reporter/issues/168 + # https://octopus.com/blog/githubactions-running-unit-tests + # https://github.com/dorny/test-reporter/issues/67 + # https://github.com/phoenix-actions/test-reporting/pull/21 + - name: Test Results + uses: phoenix-actions/test-reporting@v10 + id: test-report + if: always() + with: + name: ${{ inputs.service-name }} Test Reports + reporter: dotnet-trx + token: ${{ inputs.token }} + # only-summary: 'true' + output-to: "step-summary" + path: "**/test-results.trx" + # Set action as failed if test report contains any failed test + fail-on-error: true + ## https://github.com/dorny/test-reporter#recommended-setup-for-public-repositories + ## https://github.com/dorny/test-reporter/blob/0d9714ddc7ff86918ec725a527a3a069419d301a/src/utils/github-utils.ts#L44 + ## artifact name to download trx test result if it is in seperated workflow with github rest call, if it is not in another workflow skip this + # artifact: "' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81454dd..1d02aea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,26 +17,65 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Setup .NET - uses: actions/setup-dotnet@v2 + - name: Build and Test Flight + uses: ./.github/actions/build-test + if: success() + id: build-test-flight-step with: - dotnet-version: 7.0.x + project-path: 'src/Services/Flight/src/Flight.Api' + tests-path: 'src/Services/Flight/tests/' + # wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory + # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/ + # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not + reports-path: ${{ github.workspace }}/**/*.cobertura.xml + reports-output-path: ${{ github.workspace }}/output/test-results + service-name: 'Flight' + token: ${{ secrets.GITHUB_TOKEN }} - - name: Cache NuGet Packages - uses: actions/cache@v3 + - name: Build and Test Identity + uses: ./.github/actions/build-test + if: success() + id: build-test-identity-step with: - key: ${{ runner.os }}-dotnet-nuget - path: ~/.nuget/packages + project-path: 'src/Services/Identity/src/Identity.Api' + tests-path: 'src/Services/Identity/tests/' + # wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory + # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/ + # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not + reports-path: ${{ github.workspace }}/**/*.cobertura.xml + reports-output-path: ${{ github.workspace }}/output/test-results + service-name: 'Identity' + token: ${{ secrets.GITHUB_TOKEN }} + - name: Build and Test Passenger + uses: ./.github/actions/build-test + if: success() + id: build-test-passenger-step + with: + project-path: 'src/Services/Passenger/src/Passenger.Api' + tests-path: 'src/Services/Passenger/tests/' + # wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory + # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/ + # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not + reports-path: ${{ github.workspace }}/**/*.cobertura.xml + reports-output-path: ${{ github.workspace }}/output/test-results + service-name: 'Passenger' + token: ${{ secrets.GITHUB_TOKEN }} - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build -c Release --no-restore - - - name: Test - run: dotnet test -c Release --no-restore + - name: Build and Test Booking + uses: ./.github/actions/build-test + if: success() + id: build-test-booking-step + with: + project-path: 'src/Services/Booking/src/Booking.Api' + tests-path: 'src/Services/Booking/tests/' + # wildcard search for files with the ".cobertura.xml" extension in all subdirectories of the current directory + # https://www.jamescroft.co.uk/combining-multiple-code-coverage-results-in-azure-devops/ + # https://stackoverflow.com/questions/53255065/dotnet-unit-test-with-coverlet-how-to-get-coverage-for-entire-solution-and-not + reports-path: ${{ github.workspace }}/**/*.cobertura.xml + reports-output-path: ${{ github.workspace }}/output/test-results + service-name: 'Booking' + token: ${{ secrets.GITHUB_TOKEN }} - name: Update Release Drafter if: ${{ github.ref == 'refs/heads/main' && success() }} diff --git a/src/Services/Booking/tests/tests.sln b/src/Services/Booking/tests/tests.sln new file mode 100644 index 0000000..2e7c3aa --- /dev/null +++ b/src/Services/Booking/tests/tests.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "IntegrationTest\Integration.Test.csproj", "{AC2806BF-F80B-4075-8240-0D3E87E41FEA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC2806BF-F80B-4075-8240-0D3E87E41FEA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Services/Flight/tests/tests.sln b/src/Services/Flight/tests/tests.sln new file mode 100644 index 0000000..f3624ac --- /dev/null +++ b/src/Services/Flight/tests/tests.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndToEnd.Test", "EndToEndTest\EndToEnd.Test.csproj", "{EA6ECE87-A111-4F2A-8034-8CAEADE7F491}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "IntegrationTest\Integration.Test.csproj", "{815ED633-1B3E-4F1A-B5FB-A674AB326150}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit.Test", "UnitTest\Unit.Test.csproj", "{7472C957-FA4A-48E1-87DE-474216B35F87}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA6ECE87-A111-4F2A-8034-8CAEADE7F491}.Release|Any CPU.Build.0 = Release|Any CPU + {815ED633-1B3E-4F1A-B5FB-A674AB326150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {815ED633-1B3E-4F1A-B5FB-A674AB326150}.Debug|Any CPU.Build.0 = Debug|Any CPU + {815ED633-1B3E-4F1A-B5FB-A674AB326150}.Release|Any CPU.ActiveCfg = Release|Any CPU + {815ED633-1B3E-4F1A-B5FB-A674AB326150}.Release|Any CPU.Build.0 = Release|Any CPU + {7472C957-FA4A-48E1-87DE-474216B35F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7472C957-FA4A-48E1-87DE-474216B35F87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7472C957-FA4A-48E1-87DE-474216B35F87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7472C957-FA4A-48E1-87DE-474216B35F87}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Services/Identity/tests/tests.sln b/src/Services/Identity/tests/tests.sln new file mode 100644 index 0000000..97000aa --- /dev/null +++ b/src/Services/Identity/tests/tests.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "IntegrationTest\Integration.Test.csproj", "{76FE2BD0-B242-45DC-8361-084920CDEBB4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76FE2BD0-B242-45DC-8361-084920CDEBB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76FE2BD0-B242-45DC-8361-084920CDEBB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76FE2BD0-B242-45DC-8361-084920CDEBB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76FE2BD0-B242-45DC-8361-084920CDEBB4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Services/Passenger/tests/tests.sln b/src/Services/Passenger/tests/tests.sln new file mode 100644 index 0000000..00ced03 --- /dev/null +++ b/src/Services/Passenger/tests/tests.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "IntegrationTest\Integration.Test.csproj", "{3D9D0889-3A70-45FC-8FC0-0297F209AAB9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D9D0889-3A70-45FC-8FC0-0297F209AAB9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal