Skip to content

Conversation

takahirom
Copy link
Owner

@takahirom takahirom commented Aug 14, 2025

What

Updated Roborazzi to require ComposablePreviewScanner version 0.7.0 or higher, adding automatic version validation in the Gradle plugin to prevent compatibility issues.

Why

ComposablePreviewScanner 0.7.0 introduced breaking changes with AndroidPreviewScreenshotIdBuilder package restructuring. Without version enforcement, users with older versions would experience build failures with unclear error messages.

Summary by CodeRabbit

  • New Features
    • Enforces a minimum Composable Preview Scanner version (0.7.0) with a clear build error when using older versions.
    • Improves version resolution and comparison for more reliable validation.
  • Chores
    • Updated Composable Preview Scanner to 0.7.0 and migrated references to the common module.
    • Adjusted multiplatform sample to use the new common dependency.
  • Tests
    • Added integration tests for version enforcement.
    • Added unit tests covering version parsing and comparison.

Copy link

coderabbitai bot commented Aug 14, 2025

Walkthrough

Updates dependency coordinates to ComposablePreviewScanner 0.7.0 and shifts from jvm to common module. Adds a plugin-side minimum version check (>= 0.7.0) for the Android artifact and corresponding tests (unit and integration). Adjusts sample module dependencies and imports accordingly.

Changes

Cohort / File(s) Summary
Version catalog and sample usage
gradle/libs.versions.toml, sample-generate-preview-tests-multiplatform/build.gradle.kts, sample-generate-preview-tests-multiplatform/src/androidUnitTest/kotlin/.../MultiplatformPreviewTester.kt
Bump ComposablePreviewScanner to 0.7.0; replace jvm alias with common; update sample dependency from jvm→common; fix imports to new common package.
Plugin core: version verification
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt
Add MIN_COMPOSABLE_PREVIEW_SCANNER_VERSION=0.7.0; verify and enforce android artifact version >= 0.7.0 across configurations; include version parsing/comparison helpers (with duplicated definitions in file).
Integration test
include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt
Add test that forcing 0.6.1 causes build failure with required-version message; make dependency coordinate version-configurable (default 0.7.0).
Unit tests for version logic
include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt
Add parameterized tests for isVersionLessThan and parseVersion, covering stable, pre-release, and edge cases.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant Gradle as Gradle Build
  participant Plugin as Roborazzi Plugin
  participant Resolver as Dependency Resolver

  Dev->>Gradle: run generate preview tests
  Gradle->>Plugin: apply and configure
  Plugin->>Plugin: verifyLibraryDependencies()
  Plugin->>Resolver: locate ComposablePreviewScanner:android
  Resolver-->>Plugin: declared/resolved version
  Plugin->>Plugin: compare with MIN (0.7.0)
  alt version < 0.7.0
    Plugin-->>Gradle: throw error "0.7.0 or higher is required"
    Gradle-->>Dev: build fails
  else version >= 0.7.0
    Plugin-->>Gradle: proceed
    Gradle-->>Dev: continue tasks
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

A hop, a bump, to zero-seven-oh,
I twitch my ears—no JVM, common’s the show.
The plugin sniffs versions, strict and bright,
“Too old?” it thumps—halt the night.
Tests nibble edges, green lights grow,
Carrots compiled—onward we go! 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3e214bb and 7987621.

📒 Files selected for processing (1)
  • include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: ollama-test
  • GitHub Check: compare-screenshot-test
  • GitHub Check: test
  • GitHub Check: report
  • GitHub Check: test
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tm/composable-preview-scanner-0.7.0-requirement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (1)

352-368: Consider pre-release semantics in version comparisons (optional)

parseVersion drops non-numeric suffixes, so "0.7.0-alpha01" equals "0.7.0". If you intend pre-releases to be considered lower than stable (common practice), extend the comparator to treat versions with pre-release tags as lower when numeric parts are equal.

include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt (1)

101-101: Avoid duplicating the minimum version — reuse the plugin’s constant

To prevent drift between the plugin and tests, read the minimum required version from the plugin constant instead of hardcoding it here.

Apply this diff (after adding MIN_COMPOSABLE_PREVIEW_SCANNER_VERSION in the plugin):

-    var composablePreviewScannerVersion = "0.7.0"
+    var composablePreviewScannerVersion = MIN_COMPOSABLE_PREVIEW_SCANNER_VERSION

Note: Ensure the test source set can access the constant (internal is fine within the same module).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2401a3e and 0834bda.

📒 Files selected for processing (4)
  • gradle/libs.versions.toml (1 hunks)
  • include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt (4 hunks)
  • include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (2 hunks)
  • roborazzi-compose-preview-scanner-support/src/main/java/com/github/takahirom/roborazzi/RoborazziPreviewScannerSupport.kt (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt (2)
include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/RoborazziGradleProject.kt (1)
  • record (62-65)
include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/RoborazziGradleProjectTest.kt (1)
  • record (59-70)
🔇 Additional comments (6)
gradle/libs.versions.toml (1)

51-51: Version bump to 0.7.0 aligns with new minimum requirement — LGTM

The catalog now requires ComposablePreviewScanner 0.7.0, which matches the plugin’s validation logic and import move. No issues.

roborazzi-compose-preview-scanner-support/src/main/java/com/github/takahirom/roborazzi/RoborazziPreviewScannerSupport.kt (1)

19-19: Import path update matches 0.7.0 package move — LGTM

AndroidPreviewScreenshotIdBuilder relocated to core.screenshotid in 0.7.0. The usage remains unchanged and correct.

include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (1)

245-245: Version validation hook integrated in the verification flow — LGTM

Calling verifyComposablePreviewScannerVersion() right after dependency checks ensures early, clear failure with outdated scanner versions.

include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt (3)

75-84: Integration test for old scanner version failure — LGTM

Solid negative test. It validates the new enforcement with a clear assertion on the failure message.


183-185: Dynamic coordinate wiring for KMP androidUnitTest — LGTM

Switching to io.github.sergio-sastre.ComposablePreviewScanner:android:$composablePreviewScannerVersion enables the negative test to drive version selection.


266-267: Dynamic coordinate wiring for testImplementation — LGTM

This mirrors the KMP wiring and supports the version-driven failure path in the non-KMP case.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (1)

23-24: Good: centralized min-version constant; please remove remaining hard-coded "0.7.0" literals in tests/docs

Centralizing the minimum ComposablePreviewScanner version improves consistency and avoids drift.

Run this to ensure there are no stray "0.7.0" literals left (tests/docs/build logic):

#!/bin/bash
# Find hard-coded occurrences of "0.7.0" except in version catalogs
rg -n --hidden --glob '!.git' --glob '!**/build/**' --glob '!gradle/libs.versions.toml' $'0\\.7\\.0'
🧹 Nitpick comments (1)
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (1)

360-363: Don’t swallow resolution exceptions; log at debug for diagnosability

Currently the exception is dropped, making troubleshooting hard and flagged by detekt as SwallowedException. At minimum, log at debug.

Apply this minimal diff if you keep the current approach:

-      } catch (e: Exception) {
-        // If resolution fails, we can't determine the version
-        null
-      }
+      } catch (e: Exception) {
+        project.logger.debug("Roborazzi: Failed to resolve ComposablePreviewScanner version: ${e.message}", e)
+        null
+      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0834bda and 42bc03d.

📒 Files selected for processing (2)
  • include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt (5 hunks)
  • include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • include-build/roborazzi-gradle-plugin/src/integrationTest/java/io/github/takahirom/roborazzi/PreviewGenerateTest.kt
🧰 Additional context used
🪛 detekt (1.23.8)
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt

[warning] 360-360: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ollama-test
  • GitHub Check: report
🔇 Additional comments (1)
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (1)

247-249: LGTM: version verification is executed during configuration after dependency checks

Placing verifyComposablePreviewScannerVersion(project) after verifyLibraryDependencies(project) ensures the module exists before validating its version. Looks good.

@takahirom takahirom force-pushed the tm/composable-preview-scanner-0.7.0-requirement branch from 1d3440c to 0aba224 Compare August 14, 2025 10:47
…ibility

- Update dependency from :jvm to :common in gradle/libs.versions.toml
- Update multiplatform sample to use :common dependency instead of :jvm
- Fix import paths from jvm.common to common package
- Use version catalog for consistent dependency management

This completes the ComposablePreviewScanner 0.7.0 compatibility across all samples.
@takahirom
Copy link
Owner Author

@sergio-sastre
Could you take a look at this PR? It updates ComposablePreviewScanner to version 0.7.0 and adds version validation to show clear error messages when users have incompatible older versions. The changes help users upgrade smoothly by providing guidance when version requirements aren't met.

@sergio-sastre
Copy link
Contributor

@sergio-sastre Could you take a look at this PR? It updates ComposablePreviewScanner to version 0.7.0 and adds version validation to show clear error messages when users have incompatible older versions. The changes help users upgrade smoothly by providing guidance when version requirements aren't met.

@takahirom wow! You are super fast!
Yep, let me take a look at this, and sorry for introducing the breaking change. I was definitely not aware of it and I’m definitely planning to introduce some mechanism to avoid this happening in the future.

I’ll review it in the following hours 🙏

@takahirom
Copy link
Owner Author

takahirom commented Aug 14, 2025

I found this to be a difficult problem to avoid because I didn't know that moving APIs to a superclass is source-code compatible, but not bytecode compatible.

@sergio-sastre
Copy link
Contributor

sergio-sastre commented Aug 14, 2025

I found this to be a difficult problem to avoid because I didn't know that moving APIs to a superclass is source-code compatible, but not bytecode compatible.

Yes, I did not suspect it'd not be bytecode compatible since it is "inherited" as you said.

However, Google created the metalava tool to detect such kind of incompatibility API changes, and we're using a gradle metalava plugin in my current project at work indeed 😅.

It generates a .txt file containing the signatures of the public api and has a a validate task to verify API compatibility at all levels, doing it against that .txt file.

Integrating this in Github actions should help detect these changes at least, and that is also my idea...

@@ -327,3 +330,82 @@ private fun verifyLibraryDependencies(
)
requiredLibraries.forEach { allDependencies.checkExists(it) }
}

private fun verifyComposablePreviewScannerVersion(
project: Project
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see!
I thought that the import in the generated code was the problem, but it is in the roborazzi module that provides support for composablePreviewScanner right?

I think that would explain why it is source code compatible but not at bytecode level...

In that case I think it is only fixable by enforcing the user to use 0.7.0+ when using Roborazzi. So this looks fine :)

Copy link
Owner Author

@takahirom takahirom Aug 15, 2025

Choose a reason for hiding this comment

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

I believe the issue is a binary incompatibility. roborazzi-compose-preview-scanner-support was likely compiled against PreviewScanner 0.6.x, which included the AndroidPreviewScreenshotIdBuilder.ignoreClassName method. Since this method seems to have been removed in version 0.7.x, upgrading to it is causing the NoSuchMethodError.


class VersionComparisonTest {

@Test
Copy link
Contributor

Choose a reason for hiding this comment

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

mega minor:
I think a parameterized test makes more sense here, since Junit uses hard asserts by default: once the first assert fails, the test does not execute more code.

That is the reason why soft-assertions where created.
https://www.baeldung.com/java-assertj-soft-assertions

And with Parameterized tests, every assert would run in a separate test, which it is even better than soft-assertions when possible, in my opinion.
This should not be a blocker though, feel free to change it or not :)

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks for the tip, I wasn't aware of soft assertions! I'll take a look at the implementation, as I believe it could be helpful for our own library as well.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Ah, I see how it works now. It wraps and collects every error to create a single AssertionError. Thanks for clarifying.

Anyway, I've addressed your suggestion in this commit: 6a3c1a5

import sergio.sastre.composable.preview.scanner.jvm.common.CommonComposablePreviewScanner
import sergio.sastre.composable.preview.scanner.jvm.common.CommonPreviewInfo
import sergio.sastre.composable.preview.scanner.common.CommonComposablePreviewScanner
import sergio.sastre.composable.preview.scanner.common.CommonPreviewInfo

@OptIn(ExperimentalRoborazziApi::class)
Copy link
Contributor

Choose a reason for hiding this comment

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

This test is still not accounting for all the new preview parameters that were added to @Previews in common?

override fun test(testParameter: JUnit4TestParameter<CommonPreviewInfo>) {
    val preview = testParameter.preview
    val previewInfo = preview.previewInfo
    val screenshotName = CommonPreviewScreenshotIdBuilder(preview).build()
    val filePath = "$DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH/$screenshotName.png"
    captureRoboImage(
      filePath = filePath,
      roborazziComposeOptions = RoborazziComposeOptions {
        size(previewInfo.widthDp, previewInfo.heightDp)
        locale(previewInfo.locale)
        background(
          showBackground = previewInfo.showBackground,
          backgroundColor = previewInfo.backgroundColor
       )
      }
    )
}

And also add a preview with a given width, height and background, for instance, extra annotate one of the previews with this:

@Preview(widthDp = 400, heightDp = 400, showBackground = true, backgroundColor = 0xFF0000FF)

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks. I think we still can't use preview parameters in this PR because of these errors.
#722 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks. I think we still can't use preview parameters in this PR because of these errors. #722 (comment)

is there any reason not to update AGP?
Once updated, if I understood the errors correctly, we can fix the rest of errors by updating only the :sample-generate-preview-tests-multiplatform compileSdk to 35 right?
However, I am unsure if updating AGP might have any undesired consequence 🤔, so I understand your concern

Copy link
Owner Author

Choose a reason for hiding this comment

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

According to this compatibility guide, we would need to update to Kotlin 2.1, but it feels a bit early to adopt it. However, I think it might be acceptable to only update the AGP.
https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-compatibility-guide.html#version-compatibility

To avoid compatibility error, I need to add the following flag:
kotlin.mpp.androidGradlePluginCompatibility.nowarn=true

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see.
It's a pitty, since the example feels uncomplete and could mislead people searching for an example.
I got it working in this branch, but this is not based in the most up-to-date Roborazzi version, but the one of the old branch trying to migrate to kotlin 2.0.0 and I am sure for the sample-multiplatform module, is fine, but it would fail when executing tasks in other modules.

in the worst case, one could point out to that fork for an executable example and also mention here why it is not possible in the Roborazzi repo yet (i.e. kotlin version incompatible with kotlin multiplatform plugin).

Just a suggestion.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks. I've tried to use Compose Multiplatform 1.9.0-beta03 with Preview. We also use Kotlin Native, and it seems that it doesn't work with Kotlin 2.0.21.
#726 (comment)

Copy link
Contributor

@sergio-sastre sergio-sastre Aug 15, 2025

Choose a reason for hiding this comment

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

Unfortunately, I am not aware of any possibility to enable different kotlin and agp versions on different modules inside the same repo (We actually need that only in the sample-multiplatform module).

creating another repo with the required agp, kotlin versions and compileSdk that showcases a the use of the plugin for compose multiplatform previews in common would work, but it looks like a lot of overhead to me 😅

@takahirom
Copy link
Owner Author

takahirom commented Aug 15, 2025

However, Google created the metalava tool to detect such kind of incompatibility API changes, and we're using a gradle metalava plugin in my current project at work indeed 😅.

I wasn't introducing them intentionally to avoid slowing us down. But I think we can add and commit api.txt automatically so we don't have to fail the CI. I think we can just track the API changes.👍

I was thinking of using this library. The decision is tough because metalava is better, but it might not support KMP (klib) well. It seems that Google is using both tools.
https://github.com/Kotlin/binary-compatibility-validator

@takahirom
Copy link
Owner Author

📝


     * What went wrong:
     Execution failed for task ':sample-generate-preview-tests-multiplatform:checkDebugAarMetadata'.
     > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction
        > 25 issues were found when checking AAR metadata:
          
            1.  Dependency 'androidx.compose.material:material-ripple-android:1.8.2' requires libraries and applications that
                depend on it to compile against version 35 or later of the
                Android APIs.
          
                :sample-generate-preview-tests-multiplatform is currently compiled against android-34.
          
                Also, the maximum recommended compile SDK version for Android Gradle
                plugin 8.5.2 is 34.
          
                Recommended action: Update this project's version of the Android Gradle
                plugin to one that supports 35, then update this project to use
                compileSdk of at least 35.
          
                Note that updating a library or application's compileSdk (which
                allows newer APIs to be used) can be done separately from updating
                targetSdk (which opts the app in to new runtime behavior) and
                minSdk (which determines which devices the app can be installed
                on).
          
            2.  Dependency 'androidx.compose.ui:ui-tooling-data-android:1.9.0-rc01' requires libraries and applications that
                depend on it to compile against version 35 or later of the
                Android APIs.
          
                :sample-generate-preview-tests-multiplatform is currently compiled against android-34.
          
                Also, the maximum recommended compile SDK version for Android Gradle
                plugin 8.5.2 is 34.
          
                Recommended action: Update this project's version of the Android Gradle
                plugin to one that supports 35, then update this project to use
                compileSdk of at least 35.
          
                Note that updating a library or application's compileSdk (which
                allows newer APIs to be used) can be done separately from updating
                targetSdk (which opts the app in to new runtime behavior) and
                minSdk (which determines which devices the app can be installed
                on).
          
            3.  Dependency 'androidx.compose.ui:ui-tooling-data-android:1.9.0-rc01' requires Android Gradle plugin 8.6.0 or higher.
          
                This build currently uses Android Gradle plugin 8.5.2.
          
            4.  Dependency 'androidx.compose.foundation:foundation-layout-android:1.9.0-rc01' requires libraries and applications that
                depend on it to compile against version 35 or later of the
                Android APIs.
          
                :sample-generate-preview-tests-multiplatform is currently compiled against android-34.
          
                Also, the maximum recommended compile SDK version for Android Gradle
                plugin 8.5.2 is 34.
          
                Recommended action: Update this project's version of the Android Gradle
                plugin to one that supports 35, then update this project to use
                compileSdk of at least 35.
          
                Note that updating a library or application's compileSdk (which
                allows newer APIs to be used) can be done separately from updating
                targetSdk (which opts the app in to new runtime behavior) and
                minSdk (which determines which devices the app can be installed
                on).
          
            5.  Dependency 'androidx.compose.foundation:foundation-layout-android:1.9.0-rc01' requires Android Gradle plugin 8.6.0 or higher.
          
                This build currently uses Android Gradle plugin 8.5.2.
          
            6.  Dependency 'androidx.compose.foundation:foundation-android:1.9.0-rc01' requires libraries and applications that
                depend on it to compile against version 35 or later of the
                Android APIs.
          
                :sample-generate-preview-tests-multiplatform is currently compiled against android-34.
          
                Also, the maximum recommended compile SDK version for Android Gradle
                plugin 8.5.2 is 34.
          
                Recommended action: Update this project's version of the Android Gradle
                plugin to one that supports 35, then update this project to use
                compileSdk of at least 35.
          
                Note that updating a library or application's compileSdk (which
                allows newer APIs to be used) can be done separately from updating
                targetSdk (which opts the app in to new runtime behavior) and
                minSdk (which determines which devices the app can be installed
                on).
          
            7.  Dependency 'androidx.compose.foundation:foundation-android:1.9.0-rc01' requires Android Gradle plugin 8.6.0 or hi

- Refactor VersionComparisonTest to use data class with parameterized tests
- Separate parseVersion tests into dedicated test class
- Add preview with parameters example for future Compose Multiplatform 1.9.0+ support
- Clean up imports and test structure
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt (1)

16-23: Good move: parameterized tests address the earlier feedback

Switching to JUnit4 Parameterized with constructor injection makes each case independent and readable. This also aligns with the prior suggestion about parameterized tests.

🧹 Nitpick comments (5)
sample-generate-preview-tests-multiplatform/src/commonMain/kotlin/com/github/takahirom/preview/tests/Previews.kt (1)

25-29: Nit: Function name suggests parameters but none are present—clarify intent

To avoid confusion, clarify this is a placeholder for future parameterized previews, or actually add a preview parameter. Minimal change suggestion below adds a short KDoc and adjusts the text to reflect “placeholder”.

-@Preview
-@Composable
-fun PreviewWithParameters() {
-  Text("Preview with parameters (for future Compose Multiplatform 1.9.0+ support)!")
-}
+/**
+ * Placeholder preview to exercise scanner logic around future preview-parameters support
+ * in Compose Multiplatform 1.9.0+. This intentionally has no parameters.
+ */
+@Preview
+@Composable
+fun PreviewWithParameters() {
+  Text("Preview placeholder for future Compose Multiplatform 1.9.0+ parameters support.")
+}
include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt (4)

9-14: Use the description as the display name for parameterized cases

Right now the runner prints the whole data class in test names. Overriding toString to return description makes CI output much clearer.

Apply this diff:

-data class VersionComparisonTestCase(
-    val current: String,
-    val required: String,
-    val expected: Boolean,
-    val description: String
-)
+data class VersionComparisonTestCase(
+    val current: String,
+    val required: String,
+    val expected: Boolean,
+    val description: String
+) {
+    override fun toString(): String = description
+}

21-23: Include the index in parameterized test names for easier triage

Adding the index helps when multiple cases share similar descriptions.

-        @Parameterized.Parameters(name = "{0}")
+        @Parameterized.Parameters(name = "{index}: {0}")

24-38: Strengthen coverage with SNAPSHOT and cross-pre-release ordering (rc vs beta), plus symmetry

These additional cases lock in expected behavior for commonly seen qualifiers and symmetry around shortened versions.

                 VersionComparisonTestCase("0.7.0-alpha", "0.7.0-alpha", false, "0.7.0-alpha == 0.7.0-alpha"),
-                VersionComparisonTestCase("0.7.invalid", "0.7.0", false, "0.7.invalid == 0.7.0")
+                VersionComparisonTestCase("0.7.invalid", "0.7.0", false, "0.7.invalid == 0.7.0"),
+                VersionComparisonTestCase("0.7.0-SNAPSHOT", "0.7.0", true, "0.7.0-SNAPSHOT < 0.7.0"),
+                VersionComparisonTestCase("0.7.0-rc01", "0.7.0-beta02", false, "0.7.0-rc01 !< 0.7.0-beta02"),
+                VersionComparisonTestCase("0.7.0", "0.7", false, "0.7.0 == 0.7")

52-75: Expand parseVersion tests to lock handling of invalid numeric parts

This codifies the intended “invalid numeric -> 0” behavior and qualifier normalization for SNAPSHOT-like versions.

     @Test
     fun `parseVersion handles case insensitive qualifier`() {
         val (nums, qualifier) = parseVersion("1.2.3-BETA")
         assertEquals("Case insensitive version numeric parts", listOf(1, 2, 3), nums)
         assertEquals("Case insensitive version qualifier", "beta", qualifier)
     }
+
+    @Test
+    fun `parseVersion treats invalid numeric parts as 0`() {
+        val (nums, qualifier) = parseVersion("1.x.3-SNAPSHOT")
+        assertEquals(listOf(1, 0, 3), nums)
+        assertEquals("snapshot", qualifier)
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9edc6c1 and 6a3c1a5.

📒 Files selected for processing (3)
  • include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt (1 hunks)
  • sample-generate-preview-tests-multiplatform/src/androidUnitTest/kotlin/com/github/takahirom/preview/tests/MultiplatformPreviewTester.kt (2 hunks)
  • sample-generate-preview-tests-multiplatform/src/commonMain/kotlin/com/github/takahirom/preview/tests/Previews.kt (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • sample-generate-preview-tests-multiplatform/src/androidUnitTest/kotlin/com/github/takahirom/preview/tests/MultiplatformPreviewTester.kt
🧰 Additional context used
🧬 Code Graph Analysis (1)
include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt (1)
include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt (2)
  • isVersionLessThan (388-404)
  • parseVersion (406-411)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test
  • GitHub Check: report
  • GitHub Check: ollama-test
  • GitHub Check: test
  • GitHub Check: compare-screenshot-test
  • GitHub Check: build
  • GitHub Check: store-screenshot-test
🔇 Additional comments (3)
sample-generate-preview-tests-multiplatform/src/commonMain/kotlin/com/github/takahirom/preview/tests/Previews.kt (1)

24-29: LGTM: Adding an extra common preview is fine and aligns with MPP usage

The preview is self-contained, uses the correct MPP preview annotation, and won’t interfere with existing samples.

include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt (2)

56-60: LGTM: stable parsing assertions are accurate

Asserting numeric parts and null qualifier on stable versions matches the implementation.


42-49: No duplicate helpers found — no change required

Repo search shows a single implementation of the helpers and tests call them directly, so there’s no duplication to centralize right now.

  • Found: include-build/roborazzi-gradle-plugin/src/main/java/io/github/takahirom/roborazzi/GenerateComposePreviewRobolectricTestsExtension.kt
    • internal fun isVersionLessThan(...) — line ~388
    • internal fun parseVersion(...) — line ~406
  • Tests exercise them: include-build/roborazzi-gradle-plugin/src/test/java/io/github/takahirom/roborazzi/VersionComparisonTest.kt (snippet at lines 42–49)

If you expect reuse across other modules or projects, consider extracting to a shared Versioning.kt later; otherwise no action needed.

…tCase

Test names now show clean descriptions like '0.6.9 < 0.7.0' instead of full data class output
@sergio-sastre
Copy link
Contributor

However, Google created the metalava tool to detect such kind of incompatibility API changes, and we're using a gradle metalava plugin in my current project at work indeed 😅.

I wasn't introducing them intentionally to avoid slowing us down. But I think we can add and commit api.txt automatically so we don't have to fail the CI. I think we can just track the API changes.👍

I was thinking of using this library. The decision is tough because metalava is better, but it might not support KMP (klib) well. It seems that Google is using both tools. https://github.com/Kotlin/binary-compatibility-validator

Oh, I menat I should inteoduce it in ComposablePreviewScanner, this was definitely my bad 😅. Sprry for the confusion

Repository owner deleted a comment from github-actions bot Aug 15, 2025
@takahirom takahirom merged commit cf4b470 into main Aug 15, 2025
8 checks passed
@takahirom takahirom deleted the tm/composable-preview-scanner-0.7.0-requirement branch August 15, 2025 10:36
@coderabbitai coderabbitai bot mentioned this pull request Aug 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants