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 # Строгая сборка: 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: 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] permissions: contents: write 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 - name: Test + coverage working-directory: backend run: > dotnet test TeleWave.slnx -c Release --no-restore --collect:"XPlat Code Coverage" --results-directory ./coverage --logger "console;verbosity=normal" # Бейдж покрытия обновляем только для main (не для PR/форков): генерируем SVG и # force-пушим в отдельную orphan-ветку badges — README ссылается на её raw-URL. - name: Coverage badge if: github.event_name == 'push' && github.ref == 'refs/heads/main' working-directory: backend env: TOKEN: ${{ secrets.COVERAGE_TOKEN || secrets.GITEA_TOKEN }} run: | dotnet tool install --global dotnet-reportgenerator-globaltool export PATH="$PATH:$HOME/.dotnet/tools" reportgenerator \ "-reports:coverage/**/coverage.cobertura.xml" \ "-targetdir:coverage/badges" \ "-reporttypes:Badges" \ "-assemblyfilters:+TeleWave.Domain;+TeleWave.Application" \ "-classfilters:-System.*" BADGE=coverage/badges/badge_linecoverage.svg test -f "$BADGE" || { echo "badge not generated"; exit 1; } WORK=$(mktemp -d) cp "$BADGE" "$WORK/coverage.svg" cd "$WORK" git init -q -b badges git add coverage.svg git -c user.name=gitea-actions -c user.email=actions@local \ commit -q -m "coverage badge [skip ci]" git push -f \ "https://gitea-actions:${TOKEN}@gitea.hsrv.site/mrleo1nid/TeleWave.git" badges # Анализ 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). - name: Test + coverage if: env.SONAR_TOKEN != '' run: > dotnet test backend/TeleWave.slnx -c Release --no-build --collect:"XPlat Code Coverage;Format=opencover" --results-directory backend/coverage --logger "console;verbosity=normal" - 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 не задан — анализ пропущен."