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
12 changes: 6 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ jobs:

- name: Run instrumentation tests
id: screenshotsverify
continue-on-error: true
continue-on-error: false
uses: reactivecircus/android-emulator-runner@1dcd0090116d15e7c562f8db72807de5e036a4ed # v2.34.0
with:
api-level: 31
Expand All @@ -162,7 +162,7 @@ jobs:
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: ./gradlew connectedCheck --stacktrace
script: ./gradlew connectedCheck --stacktrace && tests/gradlew -p tests :connectedCheck --stacktrace

- name: Prevent pushing new screenshots if this is a fork
id: checkfork_screenshots
Expand All @@ -176,9 +176,9 @@ jobs:
continue-on-error: true
if: steps.screenshotsverify.outcome == 'failure' && github.event_name == 'pull_request'
run: |
echo "Pulling $(ls -1q dropshots/build/reports/androidTests/dropshots/reference/*.png | wc -l) files..."
ls -1q dropshots/build/reports/androidTests/dropshots/reference/*.png
cp dropshots/build/reports/androidTests/dropshots/reference/*.png dropshots/src/androidTest/assets/
echo "Pulling $(ls -1q tests/build/test-results/dropshots/reference/*.png | wc -l) files..."
ls -1q tests/build/test-results/dropshots/reference/*.png
cp tests/build/test-results/dropshots/reference/*.png tests/integration-test/src/androidTest/assets/

# Since commits from actions don't trigger new actions, we validate the new screenshots here
# before we commit them to ensure there isn't flakiness in the tests.
Expand Down Expand Up @@ -234,7 +234,7 @@ jobs:
uses: gradle/actions/setup-gradle@v4

- name: Upload Snapshot
run: ./gradlew publish -Pdropshots.releaseMode=true --no-daemon --no-parallel --no-configuration-cache --stacktrace
run: ./gradlew publish --no-daemon --no-parallel --no-configuration-cache --stacktrace
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }}
Expand Down
16 changes: 8 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
## [Unreleased]
[Unreleased]: https://github.com/dropbox/dropshots/compare/0.5.0...HEAD

New:
- Nothing yet!

Changed:
- Nothing yet!

Fixed:
- Nothing yet!
* Support for newDsl in Android Gradle Plugin 9.0.0
* Changes default behavior of `recordDebugAndroidTestScreenshots` task to record screenshots even
if tests fail. This behavior can be disabled by setting `dropshots.recordOnFailure = false`
on the Gradle plugin configuration.
* Exposed `Dropshots.recordScreenshots` as a public API to allow detecting whether screenshots are
being recorded in the current test run.
* Added new optional argument to `Dropshots` constructor. `rootScreenshotDirectory` allows users to
specify a custom root directory for screenshots on the device.

## [0.5.0] = 2025-04-08
[0.5.0]: https://github.com/dropbox/dropshots/releases/tags/0.5.0
Expand Down
4 changes: 4 additions & 0 deletions dropshots-gradle-plugin/api/dropshots-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public abstract class com/dropbox/dropshots/ClearScreenshotsTask : org/gradle/ap

public abstract class com/dropbox/dropshots/DropshotsExtension {
public fun <init> (Lorg/gradle/api/model/ObjectFactory;)V
public final fun getRecordOnFailure ()Lorg/gradle/api/provider/Property;
public final fun getReferenceOutputDirectory ()Lorg/gradle/api/provider/Property;
}

Expand All @@ -21,8 +22,11 @@ public abstract class com/dropbox/dropshots/PullScreenshotsTask : org/gradle/api
public fun <init> ()V
public abstract fun getAdbExecutable ()Lorg/gradle/api/provider/Property;
protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations;
protected abstract fun getFileOperations ()Lorg/gradle/api/file/FileSystemOperations;
public abstract fun getOutputDirectory ()Lorg/gradle/api/file/DirectoryProperty;
public abstract fun getReferenceOutputDirectory ()Lorg/gradle/api/provider/Property;
public abstract fun getScreenshotDir ()Lorg/gradle/api/provider/Property;
public abstract fun getShouldWriteReferences ()Lorg/gradle/api/provider/Property;
public final fun pullScreenshots ()V
}

Expand Down
86 changes: 34 additions & 52 deletions dropshots-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import com.android.build.gradle.tasks.SourceJarTask
import com.vanniktech.maven.publish.GradlePlugin
import com.vanniktech.maven.publish.JavadocJar.Dokka
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.provideDelegate
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.FileOutputStream
import java.util.Properties
import kotlin.apply

plugins {
`java-gradle-plugin`
Expand All @@ -15,31 +15,13 @@ plugins {
alias(libs.plugins.binaryCompatibilityValidator)
}

buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
}
}

repositories {
mavenCentral()
gradlePluginPortal()
}

sourceSets {
main.configure {
java.srcDir("src/generated/kotlin")
}
}

mavenPublishing {
configure(GradlePlugin(Dokka("dokkaJavadoc")))
}

val generateVersionTask = tasks.register("generateVersion") {
val generateVersionTask: TaskProvider<*> = tasks.register("generateVersion") {
inputs.property("version", project.property("VERSION_NAME") as String)
outputs.dir(project.layout.projectDirectory.dir("src/generated/kotlin"))
outputs.dir(layout.buildDirectory.dir("generated/generateVersion"))

doLast {
val output = File(outputs.files.first(), "com/dropbox/dropshots/Version.kt")
Expand All @@ -52,23 +34,9 @@ val generateVersionTask = tasks.register("generateVersion") {
}
}

tasks.withType<Jar>().configureEach {
dependsOn(generateVersionTask)
}

tasks.named("dokkaJavadoc").configure {
dependsOn(generateVersionTask)
}

tasks.named("compileKotlin").configure {
dependsOn(generateVersionTask)
}

tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
apiVersion.set(KotlinVersion.KOTLIN_1_8)
languageVersion.set(KotlinVersion.KOTLIN_1_8)
sourceSets {
main.configure {
java.srcDir(generateVersionTask.map { it.outputs.files })
}
}

Expand All @@ -77,6 +45,11 @@ tasks.withType<JavaCompile>().configureEach {
}

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
apiVersion.set(KotlinVersion.KOTLIN_2_0)
languageVersion.set(KotlinVersion.KOTLIN_2_0)
}
explicitApi()
}

Expand All @@ -89,20 +62,29 @@ gradlePlugin {
}
}

// See https://github.com/slackhq/keeper/pull/11#issuecomment-579544375 for context
val releaseMode = hasProperty("dropshots.releaseMode")
val addTestPlugin: Configuration = configurations.create("addTestPlugin") {
attributes {
attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.JAR_TYPE)
}
}

configurations { testImplementation.get().extendsFrom(addTestPlugin) }

tasks.pluginUnderTestMetadata {
// make sure the test can access plugins for coordination.
pluginClasspath.from(addTestPlugin)
}
dependencies {
addTestPlugin(gradleApi())
addTestPlugin(libs.android)
addTestPlugin(libs.kotlin.plugin)


compileOnly(gradleApi())
compileOnly(libs.android)
compileOnly(libs.kotlin.plugin)

implementation(platform(libs.kotlin.bom))
// Don't impose our version of KGP on consumers

if (releaseMode) {
compileOnly(libs.android)
compileOnly(libs.kotlin.plugin)
} else {
implementation(libs.android)
implementation(libs.kotlin.plugin)
}

testImplementation(gradleTestKit())
testImplementation(platform(libs.kotlin.bom))
Expand Down
1 change: 1 addition & 0 deletions dropshots-gradle-plugin/gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import org.gradle.api.tasks.Destroys
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecOperations
import org.gradle.work.DisableCachingByDefault

@DisableCachingByDefault(
because = "The task interacts with the connected test device, so caching is not applicable."
Comment thread
adecker89 marked this conversation as resolved.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true? These tasks still have input, so if the input hasn't changed or dependent tasks aren't executed then there should be no work to do here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean tasks generally aren't cached

but, this task should probably also have a

outputs.upToDateWhen { false }

since it interacts with adb and input tracking will not be accurate

)
public abstract class ClearScreenshotsTask : DefaultTask() {

@get:Input
Expand All @@ -22,6 +26,8 @@ public abstract class ClearScreenshotsTask : DefaultTask() {
init {
description = "Removes the test screenshots from the test device."
group = "verification"

outputs.upToDateWhen { false }
}

@TaskAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ public abstract class DropshotsExtension @Inject constructor(objects: ObjectFact
*/
public val referenceOutputDirectory: Property<String> = objects.property(String::class.java)
.convention("src/androidTest/screenshots")

/**
* Whether to record screenshots on test failure. If true and recording is enabled, the
* screenshots from the test device will be pulled and saved to the [referenceOutputDirectory]
* even if the test fails.
*/
public val recordOnFailure: Property<Boolean> = objects.property(Boolean::class.java)
.convention(true)
}
Loading
Loading