Skip to content

Commit ed73464

Browse files
runningcodeclaude
andcommitted
fix(snapshot): Use Paparazzi's default snapshot dir for sidecar metadata
Instead of configuring a custom snapshotRootDirectory on HtmlReportWriter and passing it via a sentry.snapshot.output system property, reuse the paparazzi.snapshot.dir that Paparazzi's plugin already sets. Sidecar JSON files are now written alongside golden images in the same directory. Also simplifies sidecar JSON generation using a linkedMapOf and removes dead code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e3efd18 commit ed73464

2 files changed

Lines changed: 39 additions & 85 deletions

File tree

plugin-build/src/main/kotlin/io/sentry/android/gradle/snapshot/GenerateSnapshotTestsTask.kt

Lines changed: 26 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,6 @@ private object PaparazziPreviewRule {
218218
false -> previewInfo.apiLevel
219219
}
220220
val tolerance = 0.0
221-
val sentryOutputDir = File(
222-
System.getProperty("sentry.snapshot.output", "build/sentry-snapshots")
223-
)
224221
return Paparazzi(
225222
environment = detectEnvironment().copy(compileSdkVersion = previewApiLevel),
226223
deviceConfig = DeviceConfigBuilder.build(preview.previewInfo),
@@ -234,10 +231,7 @@ private object PaparazziPreviewRule {
234231
snapshotHandler = TestNameOverrideHandler(
235232
when (System.getProperty("paparazzi.test.verify")?.toBoolean() == true) {
236233
true -> SnapshotVerifier(maxPercentDifference = tolerance)
237-
false -> HtmlReportWriter(
238-
maxPercentDifference = tolerance,
239-
snapshotRootDirectory = sentryOutputDir,
240-
)
234+
false -> HtmlReportWriter(maxPercentDifference = tolerance)
241235
}
242236
),
243237
maxPercentDifference = tolerance,
@@ -310,8 +304,6 @@ class $CLASS_NAME(
310304
.encodeUnsafeCharacters()
311305
.build()
312306
313-
writeSidecarMetadata(screenshotId, preview)
314-
315307
paparazzi.snapshot(name = screenshotId) {
316308
val previewInfo = preview.previewInfo
317309
when (previewInfo.showSystemUi) {
@@ -338,57 +330,40 @@ class $CLASS_NAME(
338330
}
339331
}
340332
}
333+
334+
writeSidecarMetadata(screenshotId, preview)
341335
}
342336
343337
private fun writeSidecarMetadata(
344338
screenshotId: String,
345339
preview: ComposablePreview<AndroidPreviewInfo>,
346340
) {
347-
val sentryRoot = File(
348-
System.getProperty("sentry.snapshot.output", "build/sentry-snapshots")
349-
)
350-
val imagesDir = File(sentryRoot, "images")
341+
val snapshotDir = File(System.getProperty("paparazzi.snapshot.dir"))
342+
val imagesDir = File(snapshotDir, "images")
351343
imagesDir.mkdirs()
352344
val info = preview.previewInfo
353-
val q = '"'
354-
val parts = mutableListOf<String>()
355-
parts.add(q + "display_name" + q + ": " + q + escapeJson(screenshotId) + q)
356-
parts.add(q + "image_file_name" + q + ": " + q + escapeJson(screenshotId) + q)
357-
parts.add(q + "className" + q + ": " + q + escapeJson(preview.declaringClass) + q)
358-
parts.add(q + "methodName" + q + ": " + q + escapeJson(preview.methodName) + q)
359-
if (info.group.isNotBlank()) {
360-
parts.add(q + "group" + q + ": " + q + escapeJson(info.group) + q)
361-
}
362-
if (info.name.isNotBlank()) {
363-
parts.add(q + "previewName" + q + ": " + q + escapeJson(info.name) + q)
364-
}
365-
if (info.locale.isNotBlank()) {
366-
parts.add(q + "locale" + q + ": " + q + escapeJson(info.locale) + q)
367-
}
368-
if (info.device.isNotBlank()) {
369-
parts.add(q + "device" + q + ": " + q + escapeJson(info.device) + q)
370-
}
371-
val nightMode = info.uiMode and 0x30 == 0x20
372-
parts.add(q + "nightMode" + q + ": " + if (nightMode) "true" else "false")
373-
if (info.fontScale != 1f) {
374-
parts.add(q + "fontScale" + q + ": " + info.fontScale)
375-
}
376-
if (info.apiLevel != -1) {
377-
parts.add(q + "apiLevel" + q + ": " + info.apiLevel)
378-
}
379-
if (info.widthDp > 0) {
380-
parts.add(q + "widthDp" + q + ": " + info.widthDp)
381-
}
382-
if (info.heightDp > 0) {
383-
parts.add(q + "heightDp" + q + ": " + info.heightDp)
384-
}
385-
if (info.showSystemUi) {
386-
parts.add(q + "showSystemUi" + q + ": true")
387-
}
388-
if (info.showBackground) {
389-
parts.add(q + "showBackground" + q + ": true")
345+
val metadata = linkedMapOf<String, Any>(
346+
"display_name" to screenshotId,
347+
"image_file_name" to screenshotId,
348+
"className" to preview.declaringClass,
349+
"methodName" to preview.methodName,
350+
)
351+
if (info.group.isNotBlank()) metadata["group"] = info.group
352+
if (info.name.isNotBlank()) metadata["previewName"] = info.name
353+
if (info.locale.isNotBlank()) metadata["locale"] = info.locale
354+
if (info.device.isNotBlank()) metadata["device"] = info.device
355+
metadata["nightMode"] = (info.uiMode and 0x30 == 0x20)
356+
if (info.fontScale != 1f) metadata["fontScale"] = info.fontScale
357+
if (info.apiLevel != -1) metadata["apiLevel"] = info.apiLevel
358+
if (info.widthDp > 0) metadata["widthDp"] = info.widthDp
359+
if (info.heightDp > 0) metadata["heightDp"] = info.heightDp
360+
if (info.showSystemUi) metadata["showSystemUi"] = true
361+
if (info.showBackground) metadata["showBackground"] = true
362+
363+
val json = metadata.entries.joinToString(",\n ", prefix = "{\n ", postfix = "\n}") { (k, v) ->
364+
if (v is String) "\"" + k + "\": \"" + escapeJson(v) + "\""
365+
else "\"" + k + "\": " + v
390366
}
391-
val json = parts.joinToString(",\n ", prefix = "{\n ", postfix = "\n}")
392367
val sidecarName = "Paparazzi_Preview_Test_" +
393368
screenshotId.lowercase(Locale.US).replace("\\s".toRegex(), "_")
394369
File(imagesDir, "${'$'}{sidecarName}.json").writeText(json)

plugin-build/src/main/kotlin/io/sentry/android/gradle/snapshot/SentrySnapshotPlugin.kt

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package io.sentry.android.gradle.snapshot
22

33
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
4-
import com.android.build.api.variant.HostTestBuilder
4+
import com.android.build.api.variant.HostTestBuilder.Companion.UNIT_TEST_TYPE
55
import com.android.build.gradle.BaseExtension
66
import io.sentry.android.gradle.util.AgpVersions
7-
import java.io.File
87
import kotlin.jvm.java
98
import org.gradle.api.Plugin
109
import org.gradle.api.Project
@@ -32,45 +31,25 @@ class SentrySnapshotPlugin : Plugin<Project> {
3231
project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
3332

3433
androidComponents.onVariants { variant ->
35-
val variantName = variant.name
36-
val sentrySnapshotRootDir =
37-
project.layout.buildDirectory.dir("sentry-snapshots/$variantName")
38-
val testTaskName = "test${variantName.replaceFirstChar { it.uppercase() }}UnitTest"
39-
project.tasks
40-
.matching { it.name == testTaskName }
41-
.configureEach { task ->
42-
val testTask = task as Test
43-
testTask.systemProperty(
44-
"sentry.snapshot.output",
45-
sentrySnapshotRootDir.get().asFile.absolutePath,
46-
)
47-
testTask.systemProperty("paparazzi.test.record", "true")
48-
testTask.doFirst {
49-
val imagesDir = File(sentrySnapshotRootDir.get().asFile, "images")
50-
if (imagesDir.exists()) {
51-
imagesDir.deleteRecursively()
52-
}
53-
}
54-
}
55-
5634
val generateTask = GenerateSnapshotTestsTask.register(project, extension, android, variant)
5735
if (AgpVersions.isAGP90(AgpVersions.CURRENT)) {
5836
// Right now it seems we only have HostTestBuilder.UNIT_TEST_TYPE as the key but we are
5937
// creating screenshot tests like HostTestBuilder.SCREENSHOT_TEST_TYPE
6038
// We should adjust this once the API is stable and documented.
61-
variant.hostTests[HostTestBuilder.UNIT_TEST_TYPE]
62-
// Using `sources?.kotlin` is broken so we have to use sources?.java:
63-
// https://issuetracker.google.com/issues/268248348
64-
?.sources
65-
?.java
66-
?.addGeneratedSourceDirectory(generateTask, GenerateSnapshotTestsTask::outputDir)
39+
variant.hostTests[UNIT_TEST_TYPE]?.apply {
40+
configureTestTask { it.systemProperty("paparazzi.test.record", "true") }
41+
sources.java?.addGeneratedSourceDirectory(
42+
generateTask,
43+
GenerateSnapshotTestsTask::outputDir
44+
)
45+
}
6746
} else {
68-
// `unitTest` is deprecated, the replacement above is complex
6947
@Suppress("DEPRECATION_ERROR")
70-
variant.unitTest
71-
?.sources
72-
?.java
73-
?.addGeneratedSourceDirectory(generateTask, GenerateSnapshotTestsTask::outputDir)
48+
// `unitTest` is deprecated, the replacement above is complex
49+
variant.unitTest?.apply {
50+
sources.java?.addGeneratedSourceDirectory(generateTask, GenerateSnapshotTestsTask::outputDir)
51+
configureTestTask { it.systemProperty("paparazzi.test.record", "true") }
52+
}
7453
}
7554
}
7655
}

0 commit comments

Comments
 (0)