From e2eb512dfa0ea747d0083e78a325abc87764c60f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=B0=D0=B6=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=90=D1=80?= =?UTF-8?q?=D1=82=D0=B5=D0=BC?= Date: Thu, 2 Oct 2025 02:49:43 +0300 Subject: [PATCH 1/2] Enhance CI configuration: add JUnit and Detekt support, streamline Dangerfile logic --- .github/workflows/review.yml | 266 +++++++++++++++++++++++++++++------ Dangerfile | 72 ++++++---- Gemfile | 7 +- 3 files changed, 276 insertions(+), 69 deletions(-) diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index 631aa53..ad7ac61 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -1,63 +1,249 @@ -name: Review PR with Danger +name: Review on: pull_request: - branches: ["develop"] - types: [opened, synchronize, closed] + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: review-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + checks: write + pull-requests: write jobs: - build: + android_build_both: runs-on: ubuntu-latest + env: + GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3g -XX:MaxMetaspaceSize=512m -Djava.awt.headless=true" -Dorg.gradle.workers.max=2 + KOTLIN_DAEMON_JVMARGS: -Xmx2048m steps: - - - name: Clone repo - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 100 - - - name: set up JDK 17 - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'temurin' - cache: gradle - - - name: Set up Ruby 3.0 - uses: actions/setup-ruby@v1 + distribution: temurin + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Assemble Android (default) + run: ./gradlew --no-daemon --stacktrace --max-workers=2 assembleDebug + - name: Enable isRelease=true + shell: bash + run: | + if [ -f settings.properties ]; then + if grep -q '^isRelease=' settings.properties; then + sed -i 's/^isRelease=.*/isRelease=true/' settings.properties + else + echo 'isRelease=true' >> settings.properties + fi + else + echo 'isRelease=true' > settings.properties + fi + - name: Assemble Android (isRelease=true) + run: ./gradlew --no-daemon --stacktrace --max-workers=2 assembleDebug - - uses: actions/cache@v4 + static_checks: + runs-on: ubuntu-latest + needs: android_build_both + env: + GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx2g -XX:MaxMetaspaceSize=512m -Djava.awt.headless=true" + steps: + - uses: actions/checkout@v4 with: - path: vendor/bundle - key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-gems- - + fetch-depth: 100 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Run Detekt + run: ./gradlew --no-daemon --stacktrace detektCheckAll + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2 + bundler-cache: true - name: Bundle install run: | - gem install bundler - bundle config path vendor/bundle + bundle config set path 'vendor/bundle' bundle install --jobs 4 --retry 3 + - name: Danger (Detekt) + env: + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SKIP_JUNIT: "1" + run: bundle exec danger --dangerfile=Dangerfile --danger_id=danger-detekt --fail-on-errors=true - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Assemble debug build - run: ./gradlew clean assembleDebug + tests_jvm: + runs-on: ubuntu-latest + needs: android_build_both + env: + GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3g -XX:MaxMetaspaceSize=512m -Djava.awt.headless=true" + KOTLIN_DAEMON_JVMARGS: -Xmx1536m + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: JVM UI tests + timeout-minutes: 15 + run: ./gradlew --no-daemon --stacktrace jvmTest + - name: Collect reports + if: always() + run: | + mkdir -p test-results + find . -type f -name "*.xml" -path "*/build/test-results/*" -print0 | xargs -0 -I{} cp "{}" test-results/ || true + - uses: actions/upload-artifact@v4 + if: always() + with: + name: jvm-tests + path: test-results + if-no-files-found: warn + retention-days: 7 - - name: Assemble stubs + tests_wasm: + runs-on: ubuntu-latest + needs: android_build_both + env: + GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx5g -XX:MaxMetaspaceSize=768m -Djava.awt.headless=true" -Dorg.gradle.workers.max=2 + KOTLIN_DAEMON_JVMARGS: -Xmx3g + ORG_GRADLE_PROJECT_kotlin.daemon.jvmargs: -Xmx3g + NODE_OPTIONS: --max-old-space-size=6144 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: corretto + java-version: 22 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: gradle/actions/setup-gradle@v4 + - name: WASM UI tests + timeout-minutes: 15 + run: ./gradlew --no-daemon --stacktrace --max-workers=2 wasmJsTest + - name: Collect reports + if: always() run: | - echo "isRelease=true" > settings.properties - ./gradlew assembleDebug + mkdir -p test-results + find . -type f -name "*.xml" -path "*/build/test-results/*" -print0 | xargs -0 -I{} cp "{}" test-results/ || true + - uses: actions/upload-artifact@v4 + if: always() + with: + name: wasm-tests + path: test-results + if-no-files-found: warn + retention-days: 7 - - name: Run Lint - run: ./gradlew lintDebug + tests_android: + runs-on: ubuntu-latest + needs: android_build_both + env: + GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3g -XX:MaxMetaspaceSize=512m -Djava.awt.headless=true" -Dorg.gradle.workers.max=2 + KOTLIN_DAEMON_JVMARGS: -Xmx2048m + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Pre-assemble Android test APKs + run: ./gradlew --no-daemon --stacktrace --max-workers=2 assembleDebug assembleAndroidTest + - name: Connected Android tests + uses: reactivecircus/android-emulator-runner@v2 + timeout-minutes: 15 + with: + api-level: 34 + target: google_apis + arch: x86_64 + profile: pixel_6 + force-avd-creation: true + emulator-boot-timeout: 180 + disable-animations: true + emulator-options: -no-snapshot -no-boot-anim -noaudio -camera-back none -camera-front none -gpu swiftshader_indirect -accel on -memory 2048 + script: ./gradlew --no-daemon --stacktrace --max-workers=1 connectedAndroidTest + - name: Collect reports + if: always() + run: | + mkdir -p test-results + find . -type f -name "*.xml" \( -path "*/build/outputs/androidTest-results/*" -o -path "*/build/reports/androidTests/connected/*" \) -print0 | xargs -0 -I{} cp "{}" test-results/ || true + - uses: actions/upload-artifact@v4 + if: always() + with: + name: android-tests + path: test-results + if-no-files-found: warn + retention-days: 7 - - name: Run Detekt - run: ./gradlew detektCheckAll + tests_ios: + runs-on: macos-latest + needs: android_build_both + env: + GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx6g -XX:MaxMetaspaceSize=1g -Djava.awt.headless=true" + KOTLIN_DAEMON_JVMARGS: -Xmx4096m + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: iOS UI tests (simulator) + timeout-minutes: 15 + run: ./gradlew --no-daemon --stacktrace iosSimulatorArm64Test + - name: Collect reports + if: always() + run: | + mkdir -p test-results + find . -type f -name "*.xml" \( -path "*/build/test-results/iosSimulatorArm64Test/*" -o -path "*/build/test-results/*/TEST-*.xml" \) -print0 | xargs -0 -I{} cp "{}" test-results/ || true + - uses: actions/upload-artifact@v4 + if: always() + with: + name: ios-tests + path: test-results + if-no-files-found: warn + retention-days: 7 - - name: Run Danger + report: + if: ${{ always() }} + runs-on: ubuntu-latest + needs: [static_checks, tests_jvm, tests_wasm, tests_android, tests_ios] + permissions: + contents: read + checks: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + continue-on-error: true + with: + pattern: "*-tests" + path: test-results + merge-multiple: true + - uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: | + test-results/**/*.xml + check_name: Unit Test Results + fail_on: nothing + - uses: ruby/setup-ruby@v1 + if: always() + with: + ruby-version: 3.2 + bundler-cache: true + - name: Bundle install + if: always() run: | - gem install danger - bundle exec danger --verbose --dangerfile=Dangerfile --danger_id=danger-pr --fail-on-errors=true + bundle config set path 'vendor/bundle' + bundle install --jobs 4 --retry 3 + - name: Danger (JUnit) + if: always() env: - DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SKIP_DETEKT: "1" + run: bundle exec danger --dangerfile=Dangerfile --danger_id=danger-tests --fail-on-errors=false diff --git a/Dangerfile b/Dangerfile index 86c4711..dd77826 100644 --- a/Dangerfile +++ b/Dangerfile @@ -1,35 +1,55 @@ +require "danger" +require "danger-kotlin_detekt" +require "danger-junit" + has_wip_label = github.pr_labels.any? { |label| label.include? "Engineers at work" } has_wip_title = github.pr_title.include? "[WIP]" -if has_wip_label || has_wip_title - warn("PR is marked as Work in Progress") -end - +warn("PR is marked as Work in Progress") if has_wip_label || has_wip_title warn("Big PR") if git.lines_of_code > 5000 -module_dirs = {} -File.foreach("settings.gradle.kts") do |line| - line.strip! - if line =~ /^project\(":(.*?)"\)\.projectDir\s*=\s*file\("([^"]+)"\)/ - module_dirs[$1] = $2 +skip_detekt = ENV["SKIP_DETEKT"] == "1" +skip_junit = ENV["SKIP_JUNIT"] == "1" + +unless skip_detekt + module_dirs = {} + if File.exist?("settings.gradle.kts") + File.foreach("settings.gradle.kts") do |line| + line = line.strip + if line =~ /^project\(":(.*?)"\)\.projectDir\s*=\s*file\("([^"]+)"\)/ + module_dirs[$1] = $2 + end + end + File.foreach("settings.gradle.kts") do |line| + line = line.strip + next unless line.start_with?("include(") + modules = line.scan(/['\"]:(.*?)['\"]/).flatten + modules.each do |mod_name| + next if module_dirs[mod_name]&.include?("sample") + base_dir = module_dirs.fetch(mod_name, mod_name) + detekt_file = File.join(base_dir, "build", "reports", "detekt", "detekt.xml") + if File.file?(detekt_file) + kotlin_detekt.report_file = detekt_file + kotlin_detekt.skip_gradle_task = true + kotlin_detekt.severity = "warning" + kotlin_detekt.filtering = true + kotlin_detekt.detekt(inline_mode: true) + else + warn("No Detekt report found in #{detekt_file} for module #{mod_name}") + end + end + end + else + warn("settings.gradle.kts not found for Detekt scan") end end -File.foreach("settings.gradle.kts") do |line| - line.strip! - next unless line.start_with?("include(") - modules = line.scan(/['\"]:(.*?)['\"]/).flatten - modules.each do |mod_name| - next if module_dirs[mod_name]&.include?("sample") - base_dir = module_dirs.fetch(mod_name, mod_name) - detekt_file = File.join(base_dir, "build", "reports", "detekt", "detekt.xml") - if File.file?(detekt_file) - kotlin_detekt.report_file = detekt_file - kotlin_detekt.skip_gradle_task = true - kotlin_detekt.severity = "warning" - kotlin_detekt.filtering = true - kotlin_detekt.detekt(inline_mode: true) - else - warn("No Detekt report found in #{detekt_file} for module #{mod_name}") - end +unless skip_junit + junit = Danger::DangerJunit.new(dangerfile: self) + files = Dir["test-results/**/*.xml"] + if files.empty? + warn("No JUnit reports found") + else + junit.parse_files(files) + junit.report end end diff --git a/Gemfile b/Gemfile index cb05f5e..7aab1d8 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,7 @@ source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } -gem 'danger' -gem 'danger-android_lint' -gem 'danger-kotlin_detekt' +gem "danger" +gem "danger-android_lint" +gem "danger-kotlin_detekt" +gem "danger-junit" From d37e76610c8317899933d456044e87d3cbbd54d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=B0=D0=B6=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=90=D1=80?= =?UTF-8?q?=D1=82=D0=B5=D0=BC?= Date: Thu, 2 Oct 2025 10:01:22 +0300 Subject: [PATCH 2/2] Enhance CI configuration --- .github/workflows/review.yml | 12 ++++++++---- Dangerfile | 20 +++++++++++++++----- Gemfile | 3 +-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index ad7ac61..002c269 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -64,10 +64,10 @@ jobs: - uses: ruby/setup-ruby@v1 with: ruby-version: 3.2 - bundler-cache: true - name: Bundle install run: | bundle config set path 'vendor/bundle' + bundle lock --add-platform x86_64-linux bundle install --jobs 4 --retry 3 - name: Danger (Detekt) env: @@ -146,6 +146,10 @@ jobs: KOTLIN_DAEMON_JVMARGS: -Xmx2048m steps: - uses: actions/checkout@v4 + - name: Install emulator deps + run: | + sudo apt-get update + sudo apt-get install -y libpulse0 - uses: actions/setup-java@v4 with: distribution: temurin @@ -162,9 +166,9 @@ jobs: arch: x86_64 profile: pixel_6 force-avd-creation: true - emulator-boot-timeout: 180 + emulator-boot-timeout: 120 disable-animations: true - emulator-options: -no-snapshot -no-boot-anim -noaudio -camera-back none -camera-front none -gpu swiftshader_indirect -accel on -memory 2048 + emulator-options: -no-snapshot -no-boot-anim -noaudio -camera-back none -camera-front none -gpu swiftshader_indirect -accel off -memory 2048 script: ./gradlew --no-daemon --stacktrace --max-workers=1 connectedAndroidTest - name: Collect reports if: always() @@ -235,11 +239,11 @@ jobs: if: always() with: ruby-version: 3.2 - bundler-cache: true - name: Bundle install if: always() run: | bundle config set path 'vendor/bundle' + bundle lock --add-platform x86_64-linux bundle install --jobs 4 --retry 3 - name: Danger (JUnit) if: always() diff --git a/Dangerfile b/Dangerfile index dd77826..357de75 100644 --- a/Dangerfile +++ b/Dangerfile @@ -1,15 +1,25 @@ require "danger" -require "danger-kotlin_detekt" -require "danger-junit" + +skip_detekt = ENV["SKIP_DETEKT"] == "1" +skip_junit = ENV["SKIP_JUNIT"] == "1" + +begin + require "danger-kotlin_detekt" unless skip_detekt +rescue LoadError + warn("danger-kotlin_detekt not available") +end + +begin + require "danger-junit" unless skip_junit +rescue LoadError + warn("danger-junit not available") +end has_wip_label = github.pr_labels.any? { |label| label.include? "Engineers at work" } has_wip_title = github.pr_title.include? "[WIP]" warn("PR is marked as Work in Progress") if has_wip_label || has_wip_title warn("Big PR") if git.lines_of_code > 5000 -skip_detekt = ENV["SKIP_DETEKT"] == "1" -skip_junit = ENV["SKIP_JUNIT"] == "1" - unless skip_detekt module_dirs = {} if File.exist?("settings.gradle.kts") diff --git a/Gemfile b/Gemfile index 7aab1d8..5627ec1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,7 @@ source "https://rubygems.org" - git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - gem "danger" gem "danger-android_lint" gem "danger-kotlin_detekt" gem "danger-junit" +gem "faraday-retry"