Publish to NuGet #35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to NuGet | |
| on: | |
| # Manual trigger | |
| workflow_dispatch: | |
| # Trigger on pull request events | |
| pull_request: | |
| # Only trigger when a pull request is closed | |
| types: [ closed ] | |
| # Only trigger for pull requests targeting the master branch | |
| branches: | |
| - master | |
| jobs: | |
| build-and-test: | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'pull_request' && github.event.pull_request.merged == true) | |
| outputs: | |
| test_passed: ${{ steps.run_tests.outputs.test_passed }} | |
| coverage_passed: ${{ steps.check_coverage.outputs.coverage_passed }} | |
| failure_reason: ${{ steps.run_tests.outputs.failure_reason }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v3 | |
| with: | |
| dotnet-version: '9.0.x' | |
| - name: Cache NuGet packages | |
| id: cache-nuget | |
| uses: actions/cache@v3 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Create temporary NuGet.Config | |
| run: | | |
| echo '<?xml version="1.0" encoding="utf-8"?> | |
| <configuration> | |
| <packageSources> | |
| <clear /> | |
| <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> | |
| </packageSources> | |
| </configuration>' > ./nuget.config | |
| - name: Restore dependencies | |
| run: dotnet restore --configfile ./nuget.config | |
| - name: Build the solution | |
| run: dotnet build --configuration Release | |
| - name: Run unit tests with coverage | |
| id: run_tests | |
| run: | | |
| if dotnet test ToolBox.Test.Units --configuration Release --collect:"XPlat Code Coverage" --logger trx; then | |
| echo "test_passed=true" >> $GITHUB_OUTPUT | |
| echo "failure_reason=" >> $GITHUB_OUTPUT | |
| else | |
| echo "test_passed=false" >> $GITHUB_OUTPUT | |
| echo "failure_reason=Test failures" >> $GITHUB_OUTPUT | |
| exit 1 | |
| fi | |
| - name: Generate and merge coverage reports | |
| id: check_coverage | |
| run: | | |
| # Install reportgenerator if not already installed | |
| dotnet tool install -g dotnet-reportgenerator-globaltool | |
| # Install libxml2-utils for xmllint | |
| sudo apt-get update | |
| sudo apt-get install -y libxml2-utils | |
| # Find all coverage.cobertura.xml files | |
| COVERAGE_FILES=$(find ToolBox.Test.Units/TestResults -name "coverage.cobertura.xml") | |
| if [ -z "$COVERAGE_FILES" ]; then | |
| echo "No coverage reports found." | |
| echo "coverage_passed=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| fi | |
| # Format the file paths as a semicolon-separated list | |
| COVERAGE_FILES_SEMICOLON=$(echo "$COVERAGE_FILES" | tr '\n' ';' | sed 's/;$//') | |
| # Merge all coverage reports into a single report | |
| reportgenerator "-reports:$COVERAGE_FILES_SEMICOLON" -targetdir:./merged-coverage-report -reporttypes:Cobertura | |
| # Use the merged report for coverage calculation | |
| MERGED_COVERAGE_FILE="./merged-coverage-report/Cobertura.xml" | |
| if [ ! -f "$MERGED_COVERAGE_FILE" ]; then | |
| echo "Merged coverage report not found." | |
| echo "coverage_passed=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| fi | |
| # Extract the line coverage percentage from the merged report | |
| COVERAGE=$(xmllint --xpath 'string(//coverage/@line-rate)' "$MERGED_COVERAGE_FILE" | awk '{print $1*100}') | |
| if [ -z "$COVERAGE" ]; then | |
| echo "Coverage report is invalid or missing coverage data." | |
| echo "coverage_passed=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| fi | |
| echo "Code Coverage: $COVERAGE%" | |
| # Check if the code coverage meets the threshold | |
| if (( $(echo "$COVERAGE > 95" | bc -l) )); then | |
| echo "Coverage threshold met." | |
| echo "coverage_passed=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "Coverage threshold not met." | |
| echo "coverage_passed=false" >> $GITHUB_OUTPUT | |
| exit 1 | |
| fi | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: ToolBox.Test.Units/TestResults | |
| - name: Upload merged coverage report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: merged-coverage-report | |
| path: ./merged-coverage-report | |
| publish: | |
| needs: build-and-test | |
| runs-on: ubuntu-latest | |
| if: needs.build-and-test.outputs.test_passed == 'true' && needs.build-and-test.outputs.coverage_passed == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v3 | |
| with: | |
| dotnet-version: '9.0.x' | |
| - name: Cache NuGet packages | |
| id: cache-nuget | |
| uses: actions/cache@v3 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Create temporary NuGet.Config | |
| run: | | |
| echo '<?xml version="1.0" encoding="utf-8"?> | |
| <configuration> | |
| <packageSources> | |
| <clear /> | |
| <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> | |
| </packageSources> | |
| </configuration>' > ./nuget.config | |
| - name: Restore dependencies | |
| run: dotnet restore --configfile ./nuget.config | |
| - name: Pack the ToolBox project | |
| run: dotnet pack ToolBox --configuration Release --output ./artifacts | |
| - name: Publish to NuGet | |
| run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json |