name: Tests on: push: branches: - main paths: - 'code/backend/**' - 'code/frontend/**' - '.github/workflows/test.yml' pull_request: paths: - 'code/backend/**' - 'code/frontend/**' - '.github/workflows/test.yml' workflow_call: inputs: ref: description: 'Git ref to checkout (branch, tag, or SHA). Defaults to the triggering ref.' type: string required: false default: '' # Cancel in-progress runs for the same PR concurrency: group: Tests-${{ inputs.ref || github.event.pull_request.number || github.ref }} cancel-in-progress: true permissions: contents: read jobs: backend: runs-on: ubuntu-latest timeout-minutes: 10 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository steps: - name: Checkout repository uses: actions/checkout@v7 timeout-minutes: 1 with: ref: ${{ inputs.ref || github.ref }} persist-credentials: false - name: Setup .NET uses: actions/setup-dotnet@v6 with: dotnet-version: 10.0.200 - name: Cache NuGet packages uses: actions/cache@v6 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json', '**/*.csproj') }} restore-keys: | ${{ runner.os }}-nuget- - name: Get vault secrets uses: hashicorp/vault-action@v4 with: url: ${{ secrets.VAULT_HOST }} method: approle roleId: ${{ secrets.VAULT_ROLE_ID }} secretId: ${{ secrets.VAULT_SECRET_ID }} secrets: secrets/data/github packages_pat | PACKAGES_PAT - name: Restore dependencies run: | dotnet nuget add source --username ${{ github.repository_owner }} --password ${{ env.PACKAGES_PAT }} --store-password-in-clear-text --name Cleanuparr https://nuget.pkg.github.com/Cleanuparr/index.json dotnet restore code/backend/cleanuparr.sln - name: Build solution run: dotnet build code/backend/cleanuparr.sln --configuration Release --no-restore - name: Run tests id: run-tests run: dotnet test code/backend/cleanuparr.sln --configuration Release --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" --settings code/backend/coverage.runsettings --results-directory ./coverage - name: Upload test results uses: actions/upload-artifact@v7 with: name: test-results path: ./coverage/*.trx retention-days: 30 - name: Upload coverage reports uses: actions/upload-artifact@v7 with: name: coverage-report path: ./coverage/**/coverage.cobertura.xml retention-days: 30 - name: Upload coverage to Codecov if: inputs.ref == '' uses: codecov/codecov-action@v7 with: files: ./coverage/**/coverage.cobertura.xml token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false flags: backend name: backend-coverage - name: Test Summary run: | echo "## Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [ "${{ steps.run-tests.outcome }}" == "success" ]; then echo "✅ All tests passed!" >> $GITHUB_STEP_SUMMARY else echo "❌ Tests failed or were cancelled. Status: ${{ steps.run-tests.outcome }}" >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY echo "Test artifacts have been uploaded for detailed analysis." >> $GITHUB_STEP_SUMMARY frontend: runs-on: ubuntu-latest timeout-minutes: 10 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository defaults: run: working-directory: code/frontend steps: - name: Checkout repository uses: actions/checkout@v7 timeout-minutes: 1 with: ref: ${{ inputs.ref || github.ref }} persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v7 with: node-version: '26' cache: 'npm' cache-dependency-path: code/frontend/package-lock.json - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Run tests run: npm run test:ci - name: Upload coverage reports uses: actions/upload-artifact@v7 with: name: frontend-coverage-report path: code/frontend/coverage/ui/lcov.info retention-days: 30 - name: Upload coverage to Codecov if: inputs.ref == '' uses: codecov/codecov-action@v7 with: files: code/frontend/coverage/ui/lcov.info token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false flags: frontend name: frontend-coverage