name: ci # Один workflow вместо трёх: порядок build → tests → sonar задаётся через `needs`, а между # отдельными файлами workflow'ов в Gitea связать этапы нечем. Побочный эффект — этапы идут # последовательно, поэтому прогон дольше, зато тесты не стартуют на заведомо битой сборке, # а анализ не уходит в SonarCloud с красными тестами. on: push: branches: [main] pull_request: workflow_dispatch: jobs: build-backend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - name: Restore working-directory: backend run: dotnet restore TeleWave.slnx # Форматирование проверяем до сборки: падает за секунду и сразу показывает, что чинить. # Версия csharpier прибита в .config/dotnet-tools.json — глобальная копия разработчика на CI # не влияет, иначе её минорка переформатировала бы репозиторий в свой стиль. - name: Format check working-directory: backend run: | dotnet tool restore dotnet csharpier check . # Строгая сборка: TreatWarningsAsErrors=true из Directory.Build.props не отключаем. - name: Build (Release) working-directory: backend run: dotnet build TeleWave.slnx -c Release --no-restore build-frontend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - name: Enable pnpm run: corepack enable - name: Install working-directory: frontend run: pnpm install --frozen-lockfile - name: Format check working-directory: frontend run: pnpm format:check - name: Lint working-directory: frontend run: pnpm lint - name: Typecheck working-directory: frontend run: pnpm typecheck - name: Build working-directory: frontend run: pnpm build tests: runs-on: ubuntu-latest needs: [build-backend, build-frontend] steps: - uses: actions/checkout@v4 - uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - name: Restore working-directory: backend run: dotnet restore TeleWave.slnx # Покрытие здесь не собираем: его считает джоба sonar своим прогоном (в формате opencover), # а бейдж покрытия в README берётся из SonarCloud. - name: Test working-directory: backend run: > dotnet test TeleWave.slnx -c Release --no-restore --logger "console;verbosity=normal" # Анализ SonarCloud вместе с покрытием: один прогон собирает решение под сканером, гоняет тесты # и отправляет результат. Только push в main — декорация pull request'ов у SonarCloud завязана # на GitHub/GitLab, из Gitea она не работает, и анализ PR только засорял бы ветки в проекте. sonar: runs-on: ubuntu-latest needs: tests if: github.event_name != 'pull_request' env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST: https://sonarcloud.io SONAR_PROJECT_KEY: mrleo1nid_telewave SONAR_ORGANIZATION: mrleo1nid steps: - uses: actions/checkout@v4 with: # Полная история — иначе Sonar не сопоставит изменения с авторами и «новым кодом». fetch-depth: 0 # Сканер — java-приложение, на runner-образе Java может не оказаться. - uses: actions/setup-java@v4 if: env.SONAR_TOKEN != '' with: distribution: temurin java-version: 21 - uses: actions/setup-dotnet@v4 if: env.SONAR_TOKEN != '' with: dotnet-version: 10.0.x - name: Install scanner if: env.SONAR_TOKEN != '' run: dotnet tool install --global dotnet-sonarscanner # Сканер запускается из корня репозитория, а не из backend/: так в анализ попадает и фронт. - name: Begin analysis if: env.SONAR_TOKEN != '' run: | export PATH="$PATH:$HOME/.dotnet/tools" dotnet sonarscanner begin \ /k:"$SONAR_PROJECT_KEY" \ /o:"$SONAR_ORGANIZATION" \ /d:sonar.host.url="$SONAR_HOST" \ /d:sonar.token="$SONAR_TOKEN" \ /d:sonar.cs.opencover.reportsPaths="**/coverage/**/coverage.opencover.xml" \ /d:sonar.exclusions="frontend/node_modules/**,frontend/dist/**,frontend/src/routeTree.gen.ts,backend/src/TeleWave.Infrastructure/Migrations/**" \ /d:sonar.coverage.exclusions="backend/src/TeleWave.Infrastructure/Migrations/**,frontend/**" # Сканер подмешивает в сборку свои анализаторы, а в проекте TreatWarningsAsErrors=true — # любое замечание Sonar роняло бы сборку вместо того, чтобы приехать в отчёт. Строгая # сборка живёт в джобе build-backend, здесь она нужна только как носитель анализа. - name: Build if: env.SONAR_TOKEN != '' run: dotnet build backend/TeleWave.slnx -c Release /p:TreatWarningsAsErrors=false # Формат opencover, а не cobertura по умолчанию: C#-анализатор Sonar читает именно его. # Интеграционные тесты без Docker пропускаются сами (см. PostgresFixture). # # Проекты гоняются по одному, а не одним прогоном по решению: при общем прогоне сборщик # покрытия теряет попадания — отчёт приезжает без модуля TeleWave.Application, и в Sonar # покрытые тестами файлы выглядят нулевыми. Отчёты складываются в один каталог, сканер # подбирает их маской. - name: Test + coverage if: env.SONAR_TOKEN != '' run: | for project in Domain Application Integration; do dotnet test "backend/tests/TeleWave.$project.Tests" \ -c Release \ --no-build \ --collect:"XPlat Code Coverage;Format=opencover" \ --results-directory backend/coverage \ --logger "console;verbosity=normal" done - name: End analysis if: env.SONAR_TOKEN != '' run: | export PATH="$PATH:$HOME/.dotnet/tools" dotnet sonarscanner end /d:sonar.token="$SONAR_TOKEN" - name: Skipped if: env.SONAR_TOKEN == '' run: echo "SONAR_TOKEN не задан — анализ пропущен."