Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ on:
types: [published]
jobs:
library:
runs-on: ubuntu-latest
runs-on: [ self-hosted-org, linux ]
container:
image: docker://docker.tuenti.io/android/novum_android:12
steps:
- name: Checkout repo
uses: actions/checkout@v4
Expand All @@ -16,10 +18,14 @@ jobs:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD }}
ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.ORG_GRADLE_PROJECT_SIGNINGKEYID }}
NEXUS_USER: ${{ secrets.NEXUS_RELEASE_USER }}
NEXUS_PASS: ${{ secrets.NEXUS_RELEASE_PASSWORD }}
run: |
./gradlew publishReleasePublicationToSonatypeRepository -DLIBRARY_VERSION=${{ github.event.release.tag_name }} --max-workers 1 closeAndReleaseStagingRepository
./gradlew publishReleasePublicationToMavenRepository -DLIBRARY_VERSION=${{ github.event.release.tag_name }}
plugin:
runs-on: ubuntu-latest
runs-on: [ self-hosted-org, linux ]
container:
image: docker://docker.tuenti.io/android/novum_android:12
steps:
- name: Checkout repo
uses: actions/checkout@v4
Expand All @@ -28,6 +34,8 @@ jobs:
env:
GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
NEXUS_USER: ${{ secrets.NEXUS_RELEASE_USER }}
NEXUS_PASS: ${{ secrets.NEXUS_RELEASE_PASSWORD }}
run: |
cd include-build
../gradlew publishPlugins -DLIBRARY_VERSION=${{ github.event.release.tag_name }}
../gradlew publishGradlePluginPublicationToMavenRepository -DLIBRARY_VERSION=${{ github.event.release.tag_name }}
1 change: 1 addition & 0 deletions android-snaptesting/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation(libs.androidx.test.monitor)
implementation(libs.androidx.test.runner)
implementation(libs.androidx.ui.test.junit4.android)
implementation(libs.espresso.core)
}

apply("${rootProject.projectDir}/mavencentral.gradle")
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ import android.app.Activity
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Looper
import android.view.View
import android.widget.EditText
import android.widget.HorizontalScrollView
import android.widget.ScrollView
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onRoot
import androidx.test.espresso.Espresso
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.screenshot.Screenshot
import com.dropbox.differ.ImageComparator
import com.dropbox.differ.Mask
Expand Down Expand Up @@ -51,7 +58,7 @@ public class ScreenshotsRule(
@RequiresApi(Build.VERSION_CODES.O)
public fun compareScreenshot(
rule: ComposeTestRule,
name: String?,
name: String? = null,
) {
rule.waitForIdle()
val bitmap = rule.onRoot().captureToImage().asAndroidBitmap()
Expand All @@ -60,16 +67,20 @@ public class ScreenshotsRule(

public fun compareScreenshot(
activity: Activity,
name: String?,
name: String? = null,
) {
val view = activity.findViewById<View>(android.R.id.content)

disableFlakyComponentsAndWaitForIdle(view)

val bitmap = Screenshot.capture(activity).bitmap
compareScreenshot(bitmap, name)
}

@Suppress("MemberVisibilityCanBePrivate")
public fun compareScreenshot(
bitmap: Bitmap,
name: String?
name: String? = null,
) {
val resourceName = "${className}_${name ?: testName}.png"
val fileName = "$resourceName.${System.nanoTime()}"
Expand Down Expand Up @@ -141,4 +152,58 @@ public class ScreenshotsRule(
)
}
}

private fun disableFlakyComponentsAndWaitForIdle(view: View? = null) {
if (view != null) {
disableAnimatedComponents(view)
}
if (notInAppMainThread()) {
waitForAnimationsToFinish()
}
}

private fun disableAnimatedComponents(view: View) {
runOnUi {
hideEditTextCursors(view)
hideScrollViewBars(view)
}
}

private fun hideEditTextCursors(view: View) {
view.childrenViews<EditText>().forEach {
it.isCursorVisible = false
}
}

private fun hideScrollViewBars(view: View) {
view.childrenViews<ScrollView>().forEach {
hideViewBars(it)
}

view.childrenViews<HorizontalScrollView>().forEach {
hideViewBars(it)
}
}

private fun hideViewBars(it: View) {
it.isHorizontalScrollBarEnabled = false
it.isVerticalScrollBarEnabled = false
it.overScrollMode = View.OVER_SCROLL_NEVER
}

public fun waitForAnimationsToFinish() {
getInstrumentation().waitForIdleSync()
Espresso.onIdle()
}

public fun runOnUi(block: () -> Unit) {
if (notInAppMainThread()) {
getInstrumentation().runOnMainSync { block() }
} else {
block()
}
}

private fun notInAppMainThread() = Looper.myLooper() != Looper.getMainLooper()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.telefonica.androidsnaptesting.screenshots

import android.view.View
import android.view.ViewGroup

@Suppress("UNCHECKED_CAST")
public inline fun <reified T : View> View.childrenViews(): List<T> = filterChildrenViews {
it is T
} as List<T>

public fun View.filterChildrenViews(filter: (View) -> Boolean): List<View> {
val children = mutableSetOf<View>()
val view = this
if (view !is ViewGroup) {
if (filter.invoke(view)) {
children.add(view)
}
} else {
for (i in 0 until view.childCount) {
view.getChildAt(i).let {
children.addAll(it.filterChildrenViews(filter))
if (filter.invoke(it)) {
children.add(it)
}
}
}
}

return children.toList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package com.telefonica.androidsnaptesting

import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.telefonica.androidsnaptesting.logs.LogsRecorder
import com.telefonica.androidsnaptesting.logs.LogsRule
import com.telefonica.androidsnaptesting.screenshots.ScreenshotsRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand Down
3 changes: 3 additions & 0 deletions include-build/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.detekt)
alias(libs.plugins.publish)
}

allprojects {
Expand All @@ -14,3 +15,5 @@ allprojects {
buildUponDefaultConfig = true
}
}

apply("${rootProject.projectDir}/../publish_maven_central.gradle")
2 changes: 2 additions & 0 deletions include-build/gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ gradlePlugin {
}
}
}

apply("${rootProject.projectDir}/mavencentral.gradle")
4 changes: 3 additions & 1 deletion include-build/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ddmlib = "31.4.1"
kotlin = "1.9.23"
detekt = "1.23.6"
publish-plugin = "1.2.0"
publish = "1.1.0"

[libraries]
android-builder-test-api = { module = "com.android.tools.build:builder-test-api", version.ref = "agp" }
Expand All @@ -15,4 +16,5 @@ android-gradle = { module = "com.android.tools.build:gradle", version.ref = "agp
[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
publish-plugin = { id = "com.gradle.plugin-publish", version.ref = "publish-plugin" }
publish-plugin = { id = "com.gradle.plugin-publish", version.ref = "publish-plugin" }
publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "publish" }
62 changes: 62 additions & 0 deletions include-build/mavencentral.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'

publishing {
repositories {
maven {
credentials {
username System.env.NEXUS_USER
password System.env.NEXUS_PASS
}
url "https://nexusng.tuenti.io/repository/maven-release-private/"
}
}
publications {
gradlePlugin(MavenPublication) {
groupId 'com.telefonica'
artifactId 'android-snaptesting-gradle-plugin'
version version

artifact("$buildDir/libs/gradle-plugin-${version}.jar")

pom {
name = 'Android Snaptesting Gradle Plugin'
description = 'Gradle Plugin for logs snapshot testing for Android Instrumentation tests.'
url = 'https://github.com/Telefonica/android-snaptesting'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'android-team-telefonica'
name = 'Android Team'
email = '[email protected]'
}
}
scm {
connection = 'scm:git:github.com/Telefonica/android-snaptesting.git'
developerConnection = 'scm:git:ssh://github.com/Telefonica/android-snaptesting.git'
url = 'https://github.com/Telefonica/android-snaptesting/tree/main'
}
withXml {
def dependenciesNode = asNode().appendNode('dependencies')

project.configurations.getByName("implementation").dependencies.each {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}
}
}
}
}

afterEvaluate {
tasks.getByName("publishGradlePluginPublicationToMavenLocal").dependsOn("jar")
tasks.getByName("publishGradlePluginPublicationToMavenRepository").dependsOn("jar")
}
10 changes: 9 additions & 1 deletion mavencentral.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ apply plugin: 'maven-publish'
apply plugin: 'signing'

publishing {
repositories {
maven {
credentials {
username System.env.NEXUS_USER
password System.env.NEXUS_PASS
}
url "https://nexusng.tuenti.io/repository/maven-release-private/"
}
}
publications {
release(MavenPublication) {
groupId 'com.telefonica'
Expand Down Expand Up @@ -59,7 +68,6 @@ publishing {

afterEvaluate {
tasks.getByName("publishReleasePublicationToMavenLocal").dependsOn("assembleRelease")
tasks.getByName("publishReleasePublicationToSonatypeRepository").dependsOn("assembleRelease")
tasks.getByName("signReleasePublication").dependsOn("assembleRelease")
}

Expand Down