Project Init

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-02 23:55:18 +01:00
commit 014d62bcc2
169 changed files with 28867 additions and 0 deletions

179
.github/workflows/coverage.yml vendored Normal file
View File

@@ -0,0 +1,179 @@
name: Code Coverage
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
coverage:
name: Generate Coverage Report
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: colaflow_test
POSTGRES_USER: colaflow_test
POSTGRES_PASSWORD: colaflow_test_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 3s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 9
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore dependencies
run: dotnet restore
working-directory: ./src
- name: Build solution
run: dotnet build --no-restore --configuration Release
working-directory: ./src
- name: Run tests with coverage
run: |
dotnet test \
--no-build \
--configuration Release \
--logger "console;verbosity=minimal" \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:CoverletOutput=./coverage/ \
/p:ExcludeByFile="**/*.g.cs,**/*.Designer.cs,**/Migrations/**" \
/p:Exclude="[*.Tests]*"
working-directory: ./tests
env:
ConnectionStrings__DefaultConnection: "Host=localhost;Port=5432;Database=colaflow_test;Username=colaflow_test;Password=colaflow_test_password"
ConnectionStrings__Redis: "localhost:6379"
- name: Install ReportGenerator
run: dotnet tool install -g dotnet-reportgenerator-globaltool
- name: Generate detailed coverage report
run: |
reportgenerator \
-reports:./tests/coverage/coverage.opencover.xml \
-targetdir:./coverage-report \
-reporttypes:"Html;Badges;TextSummary;MarkdownSummaryGithub;Cobertura"
- name: Display coverage summary
run: |
echo "## Coverage Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
cat ./coverage-report/SummaryGithub.md >> $GITHUB_STEP_SUMMARY
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: ./tests/coverage/coverage.opencover.xml
flags: unittests
name: colaflow-coverage
fail_ci_if_error: false
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
continue-on-error: true
- name: Archive coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ github.sha }}
path: ./coverage-report
retention-days: 90
- name: Generate coverage badge
run: |
# Extract line coverage percentage
COVERAGE=$(grep "Line coverage:" ./coverage-report/Summary.txt | awk '{print $3}' | sed 's/%//')
echo "COVERAGE=$COVERAGE" >> $GITHUB_ENV
# Determine badge color
if (( $(echo "$COVERAGE >= 90" | bc -l) )); then
COLOR="brightgreen"
elif (( $(echo "$COVERAGE >= 80" | bc -l) )); then
COLOR="green"
elif (( $(echo "$COVERAGE >= 70" | bc -l) )); then
COLOR="yellow"
elif (( $(echo "$COVERAGE >= 60" | bc -l) )); then
COLOR="orange"
else
COLOR="red"
fi
echo "BADGE_COLOR=$COLOR" >> $GITHUB_ENV
- name: Create coverage badge
uses: schneegans/dynamic-badges-action@v1.7.0
with:
auth: ${{ secrets.GIST_SECRET }}
gistID: your-gist-id-here
filename: colaflow-coverage.json
label: Coverage
message: ${{ env.COVERAGE }}%
color: ${{ env.BADGE_COLOR }}
continue-on-error: true
- name: Check coverage threshold
run: |
COVERAGE=$(grep "Line coverage:" ./coverage-report/Summary.txt | awk '{print $3}' | sed 's/%//')
echo "📊 Coverage Report"
echo "=================="
cat ./coverage-report/Summary.txt
echo ""
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ FAILED: Coverage $COVERAGE% is below threshold 80%"
exit 1
else
echo "✅ PASSED: Coverage $COVERAGE% meets threshold 80%"
fi
- name: Comment coverage on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summary = fs.readFileSync('./coverage-report/Summary.txt', 'utf8');
const comment = `## 📊 Code Coverage Report
${summary}
[View detailed report in artifacts](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});

220
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,220 @@
name: Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
jobs:
test:
name: Run Tests
runs-on: ubuntu-latest
strategy:
matrix:
dotnet-version: ['9.0.x']
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: colaflow_test
POSTGRES_USER: colaflow_test
POSTGRES_PASSWORD: colaflow_test_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 3s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for better coverage reports
- name: Setup .NET ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore
working-directory: ./src
- name: Build solution
run: dotnet build --no-restore --configuration Release
working-directory: ./src
- name: Run unit tests
run: |
dotnet test \
--no-build \
--configuration Release \
--filter "Category=Unit" \
--logger "trx;LogFileName=unit-tests.trx" \
--logger "console;verbosity=detailed" \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:CoverletOutput=./coverage/unit/
working-directory: ./tests
continue-on-error: true
- name: Run integration tests
run: |
dotnet test \
--no-build \
--configuration Release \
--filter "Category=Integration" \
--logger "trx;LogFileName=integration-tests.trx" \
--logger "console;verbosity=detailed" \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:CoverletOutput=./coverage/integration/
working-directory: ./tests
env:
ConnectionStrings__DefaultConnection: "Host=localhost;Port=5432;Database=colaflow_test;Username=colaflow_test;Password=colaflow_test_password"
ConnectionStrings__Redis: "localhost:6379"
continue-on-error: true
- name: Run all tests with coverage
run: |
dotnet test \
--no-build \
--configuration Release \
--logger "trx;LogFileName=all-tests.trx" \
--logger "console;verbosity=normal" \
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:CoverletOutput=./coverage/ \
/p:Threshold=80 \
/p:ThresholdType=line \
/p:ThresholdStat=total
working-directory: ./tests
- name: Generate coverage report
if: always()
run: |
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator \
-reports:./tests/coverage/coverage.opencover.xml \
-targetdir:./coverage-report \
-reporttypes:Html;Badges;TextSummary
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: ./coverage-report
retention-days: 30
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: ./tests/**/*.trx
retention-days: 30
- name: Publish test results
if: always()
uses: dorny/test-reporter@v1
with:
name: Test Results
path: ./tests/**/*.trx
reporter: dotnet-trx
fail-on-error: true
- name: Comment coverage on PR
if: github.event_name == 'pull_request'
uses: 5monkeys/cobertura-action@master
with:
path: ./tests/coverage/coverage.opencover.xml
minimum_coverage: 80
fail_below_threshold: true
- name: Check coverage threshold
run: |
if [ -f ./coverage-report/Summary.txt ]; then
cat ./coverage-report/Summary.txt
# Extract line coverage percentage
COVERAGE=$(grep "Line coverage:" ./coverage-report/Summary.txt | awk '{print $3}' | sed 's/%//')
echo "Coverage: $COVERAGE%"
# Check if coverage meets threshold
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ Coverage $COVERAGE% is below threshold 80%"
exit 1
else
echo "✅ Coverage $COVERAGE% meets threshold 80%"
fi
fi
docker-build:
name: Docker Build Test
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Test Docker Compose
run: |
docker-compose config
echo "✅ Docker Compose configuration is valid"
- name: Build Docker images (dry run)
run: |
docker-compose build --no-cache
continue-on-error: true
summary:
name: Test Summary
runs-on: ubuntu-latest
needs: [test, docker-build]
if: always()
steps:
- name: Generate summary
run: |
echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Tests | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Docker Build | ${{ needs.docker-build.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.test.result }}" == "success" ]] && [[ "${{ needs.docker-build.result }}" == "success" ]]; then
echo "✅ All checks passed!" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Some checks failed. Please review the logs." >> $GITHUB_STEP_SUMMARY
fi