From 43835a367b08f20ba7d866ab9dceadc78f61e3b8 Mon Sep 17 00:00:00 2001 From: takahirom Date: Fri, 11 Oct 2024 12:41:27 +0900 Subject: [PATCH 1/3] Fix the issue with the Roborazzi Idea Plugin not being able to display images --- roborazzi-idea-plugin/build.gradle.kts | 26 ++-- .../idea/preview/PreviewViewModel.kt | 113 +++++++++++++++--- 2 files changed, 113 insertions(+), 26 deletions(-) diff --git a/roborazzi-idea-plugin/build.gradle.kts b/roborazzi-idea-plugin/build.gradle.kts index af5e392e8..07d1963ae 100644 --- a/roborazzi-idea-plugin/build.gradle.kts +++ b/roborazzi-idea-plugin/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java") id("org.jetbrains.kotlin.jvm") - id("org.jetbrains.intellij") version "1.17.2" + id("org.jetbrains.intellij.platform") version "2.1.0" } group = "io.github.takahirom.roborazzi" @@ -13,17 +13,23 @@ repositories { // Configure Gradle IntelliJ Plugin // Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html -intellij { - updateSinceUntilBuild = false +repositories { + mavenCentral() + + intellijPlatform { + defaultRepositories() + } +} - version.set("2023.2.5") - type.set("IC") // Target IDE Platform +dependencies { + intellijPlatform { + intellijIdeaCommunity("2024.2.2", false) + bundledPlugin("com.intellij.java") + bundledPlugin("org.jetbrains.kotlin") + bundledPlugin("com.intellij.gradle") - plugins.set(listOf( - "java", - "Kotlin", - "com.intellij.gradle", - )) + instrumentationTools() + } } tasks { diff --git a/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt b/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt index 7cf719d00..b9cbd2c5d 100644 --- a/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt +++ b/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt @@ -21,6 +21,10 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.coroutines.yield +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement @@ -156,6 +160,8 @@ class PreviewViewModel { roborazziLog("fetchTasks took ${System.currentTimeMillis() - startTime}ms") } + class ReportResult(val path: String, val className: String?) + private suspend fun refreshListProcess(project: Project) { val start = System.currentTimeMillis() roborazziLog("refreshListProcess") @@ -168,7 +174,6 @@ class PreviewViewModel { lastEditingFileName.value = kotlinFile.name } val allDeclarations = kotlinFile.declarations - val allPreviewImageFiles = mutableListOf() fun hasPreviewOrTestAnnotationOrHasNameOfTestFunction(declaration: KtDeclaration): Boolean { return declaration.annotationEntries.any { annotation -> annotation.text.contains("Composable") || @@ -191,7 +196,69 @@ class PreviewViewModel { val searchPath = project.basePath statusText.value = "Searching images in $searchPath ..." + val reports = loadReports(project) + val allPreviewImageFiles = if (reports.isEmpty()) { + findImageFiles(project, classes, functions) + } else { + findImageFilesWithReports(classes, functions, reports) + } + + if (allPreviewImageFiles.isEmpty()) { + statusText.value = "No images found" + } else { + statusText.value = "${allPreviewImageFiles.size} images found" + } + val result = allPreviewImageFiles.sortedByClassesAndFunctions(classes, functions) + .map { it.path to it.lastModified() } + .distinct() + roborazziLog("refreshListProcess result.size:${result.size} by classes:${classes.map { it.name }} functions:${functions.map { it.name }} in ${System.currentTimeMillis() - start}ms") + imagesStateFlow.value = result + } + + private suspend fun loadReports(project: Project): List { + return withContext(Dispatchers.IO) { + ProjectRootManager.getInstance(project).contentRootsFromAllModules + .map { File(it.path + "/build/test-results/roborazzi/results-summary.json") } + .filter { + it.exists() + } + .flatMap { + val text = it.readText() + // It's difficult to use roborazzi-core in IntelliJ plugin so we use simple json parsing + Json.parseToJsonElement(text).jsonObject["results"]?.jsonArray?.mapNotNull { resultJson -> + ReportResult( + path = resultJson.jsonObject["golden_file_path"]?.jsonPrimitive?.content + ?: return@mapNotNull null, + className = resultJson.jsonObject["context_data"]?.jsonObject?.get("roborazzi_description_class")?.jsonPrimitive?.content + ) + }.orEmpty() + } + } + } + private suspend fun findImageFilesWithReports( + classes: List, + functions: List, + reports: List + ): MutableList { + val allPreviewImageFiles = mutableListOf() + allPreviewImageFiles.addAll( + findElementImagesWithReports(classes, reports) + .filter { it.name.contains(searchText.value, ignoreCase = true) } + ) + allPreviewImageFiles.addAll( + findElementImagesWithReports(functions, reports) + .filter { it.name.contains(searchText.value, ignoreCase = true) } + ) + roborazziLog("findImageFilesWithReports All files.size:${reports.size} -> filtered -> allPreviewImageFiles.size:${allPreviewImageFiles.size}") + return allPreviewImageFiles + } + + private suspend fun findImageFiles( + project: Project, + classes: List, + functions: List + ): MutableList { val files = withContext(Dispatchers.IO) { val roborazziFolders = ProjectRootManager.getInstance(project).contentRootsFromAllModules .map { File(it.path + AppSettingsState.instance.imagesPathForModule) } @@ -205,24 +272,17 @@ class PreviewViewModel { } } + val allPreviewImageFiles = mutableListOf() allPreviewImageFiles.addAll( - findImages(classes, files) + findElementImages(classes, files) .filter { it.name.contains(searchText.value, ignoreCase = true) } ) allPreviewImageFiles.addAll( - findImages(functions, files) + findElementImages(functions, files) .filter { it.name.contains(searchText.value, ignoreCase = true) } ) - - if (allPreviewImageFiles.isEmpty()) { - statusText.value = "No images found" - } else { - statusText.value = "${allPreviewImageFiles.size} images found" - } - val result = allPreviewImageFiles.sortedByClassesAndFunctions(classes, functions) - .map { it.path to it.lastModified() } - roborazziLog("refreshListProcess result result.size:${result.size} in ${System.currentTimeMillis() - start}ms") - imagesStateFlow.value = result + roborazziLog("findImageFiles All files.size:${files.size} -> filtered -> allPreviewImageFiles.size:${allPreviewImageFiles.size}") + return allPreviewImageFiles } private suspend fun getCurrentKtFileOrNull(project: Project): KtFile? = readAction { @@ -260,7 +320,7 @@ class PreviewViewModel { } } - private suspend fun findImages( + private suspend fun findElementImages( elements: List, files: List ): List { @@ -272,10 +332,31 @@ class PreviewViewModel { val pattern = ".*$elementName.*.png" files .filter { - val matches = it.name.matches(Regex(pattern)) + val matches = it.path.matches(Regex(pattern)) matches } - }.distinct() + } + } + } + + private suspend fun findElementImagesWithReports( + elements: List, + reports: List + ): List { + val elementNames = elements.mapNotNull { element -> + element.name + } + return withContext(Dispatchers.Default) { + elementNames.flatMap { elementName -> + val pattern = ".*$elementName.*.png" + reports + .filter { + val matches = it.path.matches(Regex(pattern)) || + it.className?.contains(elementName) == true + matches + } + } + .map { File(it.path) } } } From d640084c8ca1fa0216cee010c4ea9ed0738b117d Mon Sep 17 00:00:00 2001 From: takahirom Date: Fri, 11 Oct 2024 14:51:58 +0900 Subject: [PATCH 2/3] Add status text --- .../takahirom/roborazzi/idea/preview/PreviewViewModel.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt b/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt index b9cbd2c5d..88c44139f 100644 --- a/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt +++ b/roborazzi-idea-plugin/src/main/kotlin/com/github/takahirom/roborazzi/idea/preview/PreviewViewModel.kt @@ -197,7 +197,8 @@ class PreviewViewModel { val searchPath = project.basePath statusText.value = "Searching images in $searchPath ..." val reports = loadReports(project) - val allPreviewImageFiles = if (reports.isEmpty()) { + val useReports = reports.isEmpty() + val allPreviewImageFiles = if (useReports) { findImageFiles(project, classes, functions) } else { findImageFilesWithReports(classes, functions, reports) @@ -206,7 +207,9 @@ class PreviewViewModel { if (allPreviewImageFiles.isEmpty()) { statusText.value = "No images found" } else { - statusText.value = "${allPreviewImageFiles.size} images found" + val reportOrFiles = if (useReports) "reports" else "files" + statusText.value = + "${allPreviewImageFiles.size} images found by $reportOrFiles" } val result = allPreviewImageFiles.sortedByClassesAndFunctions(classes, functions) .map { it.path to it.lastModified() } From c951e053e712fc2a855f2c649fee99bbb86f6722 Mon Sep 17 00:00:00 2001 From: takahirom Date: Sat, 19 Oct 2024 12:44:37 +0900 Subject: [PATCH 3/3] Update Roborazzi idea plugin to 1.9.0 --- roborazzi-idea-plugin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roborazzi-idea-plugin/build.gradle.kts b/roborazzi-idea-plugin/build.gradle.kts index 07d1963ae..0be8db490 100644 --- a/roborazzi-idea-plugin/build.gradle.kts +++ b/roborazzi-idea-plugin/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "io.github.takahirom.roborazzi" -version = "1.8.0" +version = "1.9.0" repositories { mavenCentral()