From c56b0017b2512cf52bfa85df336165f177d77d9c Mon Sep 17 00:00:00 2001 From: Alexande B Date: Tue, 2 Jul 2024 10:58:06 +0200 Subject: [PATCH 1/7] ci: skip sonarqube step for PR from form #109 --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3f0f85..6f87b3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -196,22 +196,57 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - uses: actions-cool/check-user-permission@v2 + id: write_ccess + with: + require: write + username: ${{ github.triggering_actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/setup-java@v4 + if: steps.write_ccess.outputs.require-result == 'true' with: java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/actions/setup-gradle@v3 + if: steps.write_access.outputs.require-result == 'true' with: cache-read-only: false - uses: actions/cache@v4 + if: steps.write_access.outputs.require-result == 'true' with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - - env: + - run: ./gradlew sonarqube --info + if: steps.write_access.outputs.require-result == 'true' + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew sonarqube --info + - uses: peter-evans/find-comment@v3 + id: find_comment + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: SonarQube Execution + - uses: peter-evans/create-or-update-comment@v4 + if: steps.find_comment.outputs.comment-id == null && steps.write_access.outputs.require-result == 'false' + with: + body: | + SonarQube Execution Skipped. `${{ github.triggering_actor }}` does not have permissions on this repo. Maintainers will rerun it manually + edit-mode: replace + comment-id: ${{ steps.find_comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + token: ${{ secrets.GITHUB_TOKEN }} + - uses: peter-evans/create-or-update-comment@v4 + if: steps.find_comment.outputs.comment-id != null && steps.write_access.outputs.require-result == 'true' + with: + body: | + + SonarQube Execution Completed. + edit-mode: append + comment-id: ${{ steps.find_comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + token: ${{ secrets.GITHUB_TOKEN }} size-report: name: 'Diffuse report' From 124caaadbd369f94d336c14f6aed3a16d69d66fd Mon Sep 17 00:00:00 2001 From: Alex Babrykovich Date: Wed, 3 Jul 2024 14:40:11 +0200 Subject: [PATCH 2/7] ci: use fresh AVD from benchmark tests (#157) --- .github/actions/android-emulator-run/action.yml | 9 +++++++-- .github/workflows/ci.yml | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/actions/android-emulator-run/action.yml b/.github/actions/android-emulator-run/action.yml index 09288a9..6529d15 100644 --- a/.github/actions/android-emulator-run/action.yml +++ b/.github/actions/android-emulator-run/action.yml @@ -25,11 +25,16 @@ inputs: description: Emulator boot options required: true default: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + fresh-avd: + description: Force AVD creation and skip cache + required: false + default: 'false' runs: using: "composite" steps: - name: Cache AVD + if: inputs.fresh-avd != 'true' uses: actions/cache@v4 id: avd-cache with: @@ -45,7 +50,7 @@ runs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - name: 'Create AVD' - if: steps.avd-cache.outputs.cache-hit != 'true' + if: inputs.fresh-avd != 'true' && steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: arch: ${{ inputs.arch }} @@ -63,6 +68,6 @@ runs: profile: ${{ inputs.profile }} api-level: ${{ inputs.api-level }} emulator-options: ${{ inputs.boot-options }} - force-avd-creation: false + force-avd-creation: ${{ inputs.fresh-avd == 'true' }} disable-animations: true script: ${{ inputs.script }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3f0f85..56fb777 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,6 +148,7 @@ jobs: uses: ./.github/actions/android-emulator-run with: api-level: 29 + fresh-avd: true script: | adb uninstall com.hcaptcha.sdk.bench.test || true ./gradlew benchmark:connectedReleaseAndroidTest From 6cd1223c6bac14f562f98bdbe80fa0bc4ee90709 Mon Sep 17 00:00:00 2001 From: Alex Babrykovich Date: Fri, 12 Jul 2024 08:24:20 +0200 Subject: [PATCH 3/7] refactor: build gradle (#161) * chore: split big sdk/build.gradle to several applied gradle sripts * chore: upload all outputs and reports on benchmark failure * ci: move timeout restoriction to step level and reduce it to 20 * debug: enable artifact upload for success bench * fix: ignore HCaptchaWebViewHelperTest.benchmarkWebViewLoad benchmark --- .github/workflows/ci.yml | 8 +-- .../sdk/HCaptchaWebViewHelperTest.java | 2 + gradle/shared/html-java-gen.gradle | 31 +++++++++ gradle/shared/size-check.gradle | 28 ++++++++ sdk/build.gradle | 68 ++----------------- 5 files changed, 72 insertions(+), 65 deletions(-) create mode 100644 gradle/shared/html-java-gen.gradle create mode 100644 gradle/shared/size-check.gradle diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56fb777..31978dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,6 @@ jobs: # ubuntu-latest fails with JNI ERROR (app bug): weak global reference table overflow (max=51200) # macos-latest i.e. macos-14 https://github.com/ReactiveCircus/android-emulator-runner/issues/324 runs-on: macos-13 - timeout-minutes: 30 steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 @@ -146,19 +145,20 @@ jobs: cache-read-only: false - name: Run tests uses: ./.github/actions/android-emulator-run + timeout-minutes: 20 with: api-level: 29 fresh-avd: true script: | adb uninstall com.hcaptcha.sdk.bench.test || true ./gradlew benchmark:connectedReleaseAndroidTest - - if: failure() + - if: always() uses: actions/upload-artifact@v4 with: name: androidTest-benchmark-results path: | - benchmark/build/outputs/androidTest-results - benchmark/build/reports/androidTests + benchmark/build/outputs/ + benchmark/build/reports/ - name: Diff benchmark result id: diff-benchmark uses: ./.github/actions/android-benchmark-diff diff --git a/benchmark/src/androidTest/java/com/hcaptcha/sdk/HCaptchaWebViewHelperTest.java b/benchmark/src/androidTest/java/com/hcaptcha/sdk/HCaptchaWebViewHelperTest.java index af81391..feda714 100644 --- a/benchmark/src/androidTest/java/com/hcaptcha/sdk/HCaptchaWebViewHelperTest.java +++ b/benchmark/src/androidTest/java/com/hcaptcha/sdk/HCaptchaWebViewHelperTest.java @@ -10,12 +10,14 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.util.concurrent.CountDownLatch; +@Ignore("https://github.com/hCaptcha/hcaptcha-android-sdk/issues/101") @RunWith(AndroidJUnit4.class) public class HCaptchaWebViewHelperTest { @Rule diff --git a/gradle/shared/html-java-gen.gradle b/gradle/shared/html-java-gen.gradle new file mode 100644 index 0000000..e96b8ff --- /dev/null +++ b/gradle/shared/html-java-gen.gradle @@ -0,0 +1,31 @@ +android.libraryVariants.all { variant -> + def packageName = android.namespace + def variantName = variant.name.capitalize() + def outputDir = file("${project.buildDir}/generated/source/hcaptcha/${variant.name}/${packageName.replaceAll('\\.', '/')}") + def generateTask = project.task("generate${variantName}JavaClassFromStaticHtml") { + group 'Generate' + description "Generate HTML java class" + + doFirst { + def outputJavaClass = file("$outputDir/HCaptchaHtml.java") + def template = file("$projectDir/src/main/html/HCaptchaHtml.java.tml").text + def html = file("$projectDir/src/main/html/hcaptcha.html") + .readLines() + .stream() + .map({l -> "\"${l.replaceAll('"', '\\\\"')}\\n\""}) + .collect(java.util.stream.Collectors.joining("\n${' ' * 16}+ ")) + + def engine = new groovy.text.SimpleTemplateEngine() + def src = engine.createTemplate(template).make([ + "htmlContent": html, + "packageName": packageName + ]) + + outputDir.mkdirs() + outputJavaClass.write(src.toString()) + } + } + + // preBuild.dependsOn generateTask + variant.registerJavaGeneratingTask(generateTask, outputDir) +} \ No newline at end of file diff --git a/gradle/shared/size-check.gradle b/gradle/shared/size-check.gradle new file mode 100644 index 0000000..6bf0817 --- /dev/null +++ b/gradle/shared/size-check.gradle @@ -0,0 +1,28 @@ +android.libraryVariants.all { variant -> + def variantName = variant.name.capitalize() + project.task("report${variantName}AarSize") { + group 'Help' + description "Report ${variant.name} AAR size" + dependsOn variant.packageLibraryProvider + + doFirst { + var aarPath = variant.packageLibraryProvider.get().archiveFile.get().getAsFile() + long aarSizeKb = aarPath.length() / 1024 + println("File ${aarPath} is ${aarSizeKb}Kbyte") + } + } + + project.tasks.findByName("check").dependsOn(project.task("check${variantName}AarSize") { + group 'Verification' + description "Checks ${variant.name} AAR size doesn't exceed ${project.ext}Kb" + dependsOn variant.packageLibraryProvider + + doFirst { + var aarFile = variant.packageLibraryProvider.get().archiveFile.get().getAsFile() + long aarSizeKb = aarFile.length() / 1024 + if (aarSizeKb > maxAarSizeKb) { + throw new GradleException("${aarPath} size exceeded! ${aarSizeKb}Kbyte > ${MAX_AAR_SIZE_KB}Kbyte") + } + } + }) +} \ No newline at end of file diff --git a/sdk/build.gradle b/sdk/build.gradle index f78c5dd..e5c9878 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -9,6 +9,10 @@ plugins { id "org.sonarqube" version "3.4.0.2513" } +ext { + maxAarSizeKb = 200 +} + android { compileSdk 34 namespace 'com.hcaptcha.sdk' @@ -111,64 +115,6 @@ project.afterEvaluate { } } -long MAX_AAR_SIZE_KB = 200 - -android.libraryVariants.all { variant -> - def variantName = variant.name.capitalize() - project.task("report${variantName}AarSize") { - group 'Help' - description "Report ${variant.name} AAR size" - dependsOn variant.packageLibraryProvider - - doFirst { - var aarPath = variant.packageLibraryProvider.get().archiveFile.get().getAsFile() - long aarSizeKb = aarPath.length() / 1024 - println("File ${aarPath} is ${aarSizeKb}Kbyte") - } - } - - project.tasks.findByName("check").dependsOn(project.task("check${variantName}AarSize") { - group 'Verification' - description "Checks ${variant.name} AAR size doesn't exceed ${MAX_AAR_SIZE_KB}Kb" - dependsOn variant.packageLibraryProvider - - doFirst { - var aarFile = variant.packageLibraryProvider.get().archiveFile.get().getAsFile() - long aarSizeKb = aarFile.length() / 1024 - if (aarSizeKb > MAX_AAR_SIZE_KB) { - throw new GradleException("${aarPath} size exceeded! ${aarSizeKb}Kbyte > ${MAX_AAR_SIZE_KB}Kbyte") - } - } - }) - - def packageName = "com.hcaptcha.sdk" - def outputDir = file("${project.buildDir}/generated/source/hcaptcha/${variant.name}/${packageName.replaceAll('\\.', '/')}") - def generateTask = project.task("generate${variantName}JavaClassFromStaticHtml") { - group 'Generate' - description "Generate HTML java class" - - doFirst { - def outputJavaClass = file("$outputDir/HCaptchaHtml.java") - def template = file("$projectDir/src/main/html/HCaptchaHtml.java.tml").text - def html = file("$projectDir/src/main/html/hcaptcha.html") - .readLines() - .stream() - .map({l -> "\"${l.replaceAll('"', '\\\\"')}\\n\""}) - .collect(java.util.stream.Collectors.joining("\n${' ' * 16}+ ")) - - def engine = new groovy.text.SimpleTemplateEngine() - def src = engine.createTemplate(template).make([ - "htmlContent": html, - "packageName": packageName - ]) - - outputDir.mkdirs() - outputJavaClass.write(src.toString()) - } - } - - // preBuild.dependsOn generateTask - variant.registerJavaGeneratingTask(generateTask, outputDir) -} - -apply from: "$rootProject.projectDir/gradle/shared/code-quality.gradle" \ No newline at end of file +apply from: "$rootProject.projectDir/gradle/shared/code-quality.gradle" +apply from: "$rootProject.projectDir/gradle/shared/size-check.gradle" +apply from: "$rootProject.projectDir/gradle/shared/html-java-gen.gradle" \ No newline at end of file From 1a8702139f5845d325ec2247eedf256fb0acca87 Mon Sep 17 00:00:00 2001 From: Alexande B Date: Tue, 2 Jul 2024 10:58:06 +0200 Subject: [PATCH 4/7] ci: skip sonarqube step for PR from form #109 --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31978dc..e369fa6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -197,22 +197,57 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - uses: actions-cool/check-user-permission@v2 + id: write_ccess + with: + require: write + username: ${{ github.triggering_actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/setup-java@v4 + if: steps.write_ccess.outputs.require-result == 'true' with: java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/actions/setup-gradle@v3 + if: steps.write_access.outputs.require-result == 'true' with: cache-read-only: false - uses: actions/cache@v4 + if: steps.write_access.outputs.require-result == 'true' with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - - env: + - run: ./gradlew sonarqube --info + if: steps.write_access.outputs.require-result == 'true' + env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: ./gradlew sonarqube --info + - uses: peter-evans/find-comment@v3 + id: find_comment + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: SonarQube Execution + - uses: peter-evans/create-or-update-comment@v4 + if: steps.find_comment.outputs.comment-id == null && steps.write_access.outputs.require-result == 'false' + with: + body: | + SonarQube Execution Skipped. `${{ github.triggering_actor }}` does not have permissions on this repo. Maintainers will rerun it manually + edit-mode: replace + comment-id: ${{ steps.find_comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + token: ${{ secrets.GITHUB_TOKEN }} + - uses: peter-evans/create-or-update-comment@v4 + if: steps.find_comment.outputs.comment-id != null && steps.write_access.outputs.require-result == 'true' + with: + body: | + + SonarQube Execution Completed. + edit-mode: append + comment-id: ${{ steps.find_comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + token: ${{ secrets.GITHUB_TOKEN }} size-report: name: 'Diffuse report' From 57aa7fdfe5394a9b9a4601b808462ec6f86aa168 Mon Sep 17 00:00:00 2001 From: Alexande B Date: Fri, 12 Jul 2024 22:47:19 +0200 Subject: [PATCH 5/7] ci: migrate to own check-user-permission action --- .../actions/check-user-permission/action.yml | 48 +++++++++++++++++++ .github/workflows/ci.yml | 22 ++++----- 2 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 .github/actions/check-user-permission/action.yml diff --git a/.github/actions/check-user-permission/action.yml b/.github/actions/check-user-permission/action.yml new file mode 100644 index 0000000..ddebdaf --- /dev/null +++ b/.github/actions/check-user-permission/action.yml @@ -0,0 +1,48 @@ +name: Check User Permission +description: Checks if the user has the required permission level. + +inputs: + token: + description: Secret GitHub API token to use for making API requests. + default: ${{ github.token }} + required: true + require: + description: 'Permission level to check against (admin, write, read)' + default: write + required: true + +outputs: + granted: + description: 'true if the user has the required permission, false otherwise' + permission: + description: actual user permission (admin, write, read) + +runs: + using: "composite" + steps: + - name: Check user permission + id: check + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.token }} + OWNER: ${{ github.repository_owner }} + REPO: ${{ github.event.repository.name }} + USERNAME: ${{ github.triggering_actor }} + PERMISSION: ${{ inputs.require }} + run: | + # Fetch the collaborator permission level using the GitHub API + response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$OWNER/$REPO/collaborators/$USERNAME/permission") + + # Extract the permission level from the JSON response + user_permission=$(echo $response | jq -r '.permission') + echo "permission=${user_permission}" >> $GITHUB_OUTPUT + + # Compare the permission level with the required permission + if [[ "$user_permission" == "$PERMISSION" || ( "$user_permission" == "admin" && "$PERMISSION" == "write" ) ]]; then + echo "User has the required permission." + echo "granted=true" >> $GITHUB_OUTPUT + else + echo "User does not have the required permission." + echo "granted=false" >> $GITHUB_OUTPUT + fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e369fa6..b178b50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ on: pull_request: paths-ignore: - '**.md' + workflow_dispatch: env: JAVA_VERSION: '17' @@ -197,30 +198,25 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions-cool/check-user-permission@v2 - id: write_ccess - with: - require: write - username: ${{ github.triggering_actor }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: ./.github/actions/check-user-permission + id: write_access - uses: actions/setup-java@v4 - if: steps.write_ccess.outputs.require-result == 'true' + if: steps.write_access.outputs.granted == 'true' with: java-version: ${{ env.JAVA_VERSION }} distribution: adopt - uses: gradle/actions/setup-gradle@v3 - if: steps.write_access.outputs.require-result == 'true' + if: steps.write_access.outputs.granted == 'true' with: cache-read-only: false - uses: actions/cache@v4 - if: steps.write_access.outputs.require-result == 'true' + if: steps.write_access.outputs.granted == 'true' with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - run: ./gradlew sonarqube --info - if: steps.write_access.outputs.require-result == 'true' + if: steps.write_access.outputs.granted == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -230,7 +226,7 @@ jobs: issue-number: ${{ github.event.pull_request.number }} body-includes: SonarQube Execution - uses: peter-evans/create-or-update-comment@v4 - if: steps.find_comment.outputs.comment-id == null && steps.write_access.outputs.require-result == 'false' + if: steps.find_comment.outputs.comment-id == null && steps.write_access.outputs.granted == 'false' with: body: | SonarQube Execution Skipped. `${{ github.triggering_actor }}` does not have permissions on this repo. Maintainers will rerun it manually @@ -239,7 +235,7 @@ jobs: issue-number: ${{ github.event.pull_request.number }} token: ${{ secrets.GITHUB_TOKEN }} - uses: peter-evans/create-or-update-comment@v4 - if: steps.find_comment.outputs.comment-id != null && steps.write_access.outputs.require-result == 'true' + if: steps.find_comment.outputs.comment-id != null && steps.write_access.outputs.granted == 'true' with: body: | From 130b2e90e4592c9249ed2d6124e02942e6d0d25c Mon Sep 17 00:00:00 2001 From: Alexande B Date: Fri, 12 Jul 2024 23:06:40 +0200 Subject: [PATCH 6/7] fix: bad prior merge --- .github/workflows/ci.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbdae64..f19d14f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -198,13 +198,6 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions-cool/check-user-permission@v2 - id: write_ccess - with: - require: write - username: ${{ github.triggering_actor }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: ./.github/actions/check-user-permission id: write_access with: @@ -229,6 +222,12 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + - uses: peter-evans/find-comment@v3 + id: find_comment + with: + issue-number: ${{ github.event.pull_request.number }} + body-includes: SonarQube Execution + - uses: peter-evans/create-or-update-comment@v4 if: steps.find_comment.outputs.comment-id == null && steps.write_access.outputs.granted == 'false' with: body: | From 66a630bbe92f6826bd560709efc28ca6204cbc8c Mon Sep 17 00:00:00 2001 From: Alexande B Date: Fri, 12 Jul 2024 23:53:40 +0200 Subject: [PATCH 7/7] fix: add value to outputs of check-user-permission action --- .github/actions/check-user-permission/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/check-user-permission/action.yml b/.github/actions/check-user-permission/action.yml index ddebdaf..521b28f 100644 --- a/.github/actions/check-user-permission/action.yml +++ b/.github/actions/check-user-permission/action.yml @@ -14,8 +14,10 @@ inputs: outputs: granted: description: 'true if the user has the required permission, false otherwise' + value: ${{ steps.check.outputs.granted }} permission: description: actual user permission (admin, write, read) + value: ${{ steps.check.outputs.permission }} runs: using: "composite"