-
-
Notifications
You must be signed in to change notification settings - Fork 36
Store stability output of Android variants to their own folder #150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,68 +58,73 @@ public class ComposableStabilityCollector(private val project: Project) { | |
| val contentRoots = moduleRootManager.contentRoots | ||
|
|
||
| for (contentRoot in contentRoots) { | ||
| // Look for build/stability/stability-info.json | ||
| val jsonFile = File(contentRoot.path, "build/stability/stability-info.json") | ||
| if (!jsonFile.exists()) { | ||
| continue | ||
| } | ||
|
|
||
| try { | ||
| val jsonContent = jsonFile.readText() | ||
| val jsonObject = JsonParser.parseString(jsonContent).asJsonObject | ||
| val composablesArray = jsonObject.getAsJsonArray("composables") | ||
| val rootStabilityFolder = File(contentRoot.path, "build/stability") | ||
| val variantFolders = rootStabilityFolder.listFiles().orEmpty().filter { it.isDirectory } | ||
| val allStabilityFolders = variantFolders + rootStabilityFolder | ||
| for (folder in allStabilityFolders) { | ||
|
Comment on lines
+63
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve variant identity or dedupe before building stats. The collector now merges Also applies to: 110-123, 133-136 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is a good point, but I feel extra UI is out of scope for this PR. What do you think @skydoves? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // Look for build/stability/stability-info.json | ||
| val jsonFile = File(folder, "stability-info.json") | ||
| if (!jsonFile.exists()) { | ||
| continue | ||
| } | ||
|
|
||
| for (composableElement in composablesArray) { | ||
| val composableJson = composableElement.asJsonObject | ||
| try { | ||
| val jsonContent = jsonFile.readText() | ||
| val jsonObject = JsonParser.parseString(jsonContent).asJsonObject | ||
| val composablesArray = jsonObject.getAsJsonArray("composables") | ||
|
|
||
| // Skip anonymous composables | ||
| val simpleName = composableJson.get("simpleName").asString | ||
| if (simpleName == "<anonymous>") { | ||
| continue | ||
| } | ||
| for (composableElement in composablesArray) { | ||
| val composableJson = composableElement.asJsonObject | ||
|
|
||
| val qualifiedName = composableJson.get("qualifiedName").asString | ||
| val skippable = composableJson.get("skippable").asBoolean | ||
| val restartable = composableJson.get("restartable").asBoolean | ||
|
|
||
| // Parse parameters | ||
| val parametersArray = composableJson.getAsJsonArray("parameters") | ||
| val parameters = parametersArray.map { paramElement -> | ||
| val paramJson = paramElement.asJsonObject | ||
| val stability = paramJson.get("stability").asString | ||
| ParameterInfo( | ||
| name = paramJson.get("name").asString, | ||
| type = paramJson.get("type").asString, | ||
| isStable = stability == "STABLE", | ||
| isRuntime = stability == "RUNTIME", | ||
| ) | ||
| } | ||
| // Skip anonymous composables | ||
| val simpleName = composableJson.get("simpleName").asString | ||
| if (simpleName == "<anonymous>") { | ||
| continue | ||
| } | ||
|
|
||
| // Try to find the source file and line number | ||
| val (filePath, fileName, line) = | ||
| ReadAction.compute<Triple<String, String, Int>, Exception> { | ||
| findSourceLocation(qualifiedName, simpleName) | ||
| val qualifiedName = composableJson.get("qualifiedName").asString | ||
| val skippable = composableJson.get("skippable").asBoolean | ||
| val restartable = composableJson.get("restartable").asBoolean | ||
|
|
||
| // Parse parameters | ||
| val parametersArray = composableJson.getAsJsonArray("parameters") | ||
| val parameters = parametersArray.map { paramElement -> | ||
| val paramJson = paramElement.asJsonObject | ||
| val stability = paramJson.get("stability").asString | ||
| ParameterInfo( | ||
| name = paramJson.get("name").asString, | ||
| type = paramJson.get("type").asString, | ||
| isStable = stability == "STABLE", | ||
| isRuntime = stability == "RUNTIME", | ||
| ) | ||
| } | ||
|
|
||
| val packageName = qualifiedName.substringBeforeLast(".$simpleName", "") | ||
|
|
||
| composables.add( | ||
| ComposableInfo( | ||
| functionName = simpleName, | ||
| moduleName = module.name, | ||
| packageName = packageName.ifEmpty { "<default>" }, | ||
| fileName = fileName, | ||
| filePath = filePath, | ||
| line = line, | ||
| isSkippable = skippable, | ||
| isRestartable = restartable, | ||
| isRuntime = !skippable && restartable, | ||
| parameters = parameters, | ||
| ), | ||
| ) | ||
| // Try to find the source file and line number | ||
| val (filePath, fileName, line) = | ||
| ReadAction.compute<Triple<String, String, Int>, Exception> { | ||
| findSourceLocation(qualifiedName, simpleName) | ||
| } | ||
|
|
||
| val packageName = qualifiedName.substringBeforeLast(".$simpleName", "") | ||
|
|
||
| composables.add( | ||
| ComposableInfo( | ||
| functionName = simpleName, | ||
| moduleName = module.name, | ||
| packageName = packageName.ifEmpty { "<default>" }, | ||
| fileName = fileName, | ||
| filePath = filePath, | ||
| line = line, | ||
| isSkippable = skippable, | ||
| isRestartable = restartable, | ||
| isRuntime = !skippable && restartable, | ||
| parameters = parameters, | ||
| ), | ||
| ) | ||
| } | ||
| } catch (e: Exception) { | ||
| // Skip modules that fail to parse | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
| } catch (e: Exception) { | ||
| // Skip modules that fail to parse | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,12 +72,6 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| } else { | ||
| registerTasksAndroid(target, extension, androidComponents) | ||
| } | ||
|
|
||
| // Add output parameter to the Kotlin tasks to ensure it is compatible with the Build Cache | ||
| target.tasks.withType(KotlinCompile::class.java).configureEach { | ||
| val stabilityDir = target.layout.buildDirectory.dir("stability").get() | ||
| outputs.dir(stabilityDir).optional(true) | ||
| } | ||
| } | ||
|
|
||
| private fun registerTasksNonAndroid( | ||
|
|
@@ -93,6 +87,9 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| stabilityInputFiles.setFrom( | ||
| target.layout.buildDirectory.file("stability/stability-info.json"), | ||
| ) | ||
| stabilityInputFiles.setFrom( | ||
| target.layout.buildDirectory.file("stability/test/stability-info.json"), | ||
| ) | ||
|
Comment on lines
87
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Second
🐛 Proposed fix stabilityInputFiles.setFrom(
target.layout.buildDirectory.file("stability/stability-info.json"),
)
- stabilityInputFiles.setFrom(
+ stabilityInputFiles.from(
target.layout.buildDirectory.file("stability/test/stability-info.json"),
)🤖 Prompt for AI Agents |
||
| outputDir.set(extension.stabilityValidation.outputDir) | ||
| ignoredPackages.set(extension.stabilityValidation.ignoredPackages) | ||
| ignoredClasses.set(extension.stabilityValidation.ignoredClasses) | ||
|
|
@@ -109,6 +106,9 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| stabilityInputFiles.from( | ||
| target.layout.buildDirectory.file("stability/stability-info.json"), | ||
| ) | ||
| stabilityInputFiles.from( | ||
| target.layout.buildDirectory.file("stability/test/stability-info.json"), | ||
| ) | ||
| stabilityReferenceFiles.from(extension.stabilityValidation.outputDir) | ||
| ignoredPackages.set(extension.stabilityValidation.ignoredPackages) | ||
| ignoredClasses.set(extension.stabilityValidation.ignoredClasses) | ||
|
|
@@ -131,6 +131,21 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| configureTaskDependencies(target, extension, null, stabilityDumpTask, stabilityCheckTask) | ||
| addRuntimeDependency(target) | ||
| } | ||
|
|
||
| // Add output parameter to the Kotlin tasks to ensure it is compatible with the Build Cache | ||
| target.tasks.withType(KotlinCompile::class.java) | ||
| .named { | ||
| isKotlinTaskApplicable( | ||
| it, | ||
| extension.stabilityValidation.includeTests.get(), | ||
| ) | ||
| } | ||
| .configureEach { | ||
| val stabilityDir = target.layout.buildDirectory | ||
| .dir(getKotlinTaskStabilityFolderName(project, name)) | ||
| .get() | ||
| outputs.dir(stabilityDir).optional(true) | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| private fun registerTasksAndroid( | ||
|
|
@@ -158,7 +173,17 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| ) { | ||
| projectName.set(target.name) | ||
| stabilityInputFiles.setFrom( | ||
| target.layout.buildDirectory.file("stability/stability-info.json"), | ||
| target.layout.buildDirectory.file("stability/${variant.name}/stability-info.json"), | ||
| ) | ||
| stabilityInputFiles.setFrom( | ||
| target.layout.buildDirectory.file( | ||
| "stability/${variant.name}UnitTest/stability-info.json", | ||
| ), | ||
| ) | ||
| stabilityInputFiles.setFrom( | ||
| target.layout.buildDirectory.file( | ||
| "stability/${variant.name}AndroidTest/stability-info.json", | ||
| ), | ||
| ) | ||
|
Comment on lines
175
to
187
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Repeated Same issue as the non-Android path—each 🐛 Proposed fix stabilityInputFiles.setFrom(
target.layout.buildDirectory.file("stability/${variant.name}/stability-info.json"),
)
- stabilityInputFiles.setFrom(
+ stabilityInputFiles.from(
target.layout.buildDirectory.file(
"stability/${variant.name}UnitTest/stability-info.json",
),
)
- stabilityInputFiles.setFrom(
+ stabilityInputFiles.from(
target.layout.buildDirectory.file(
"stability/${variant.name}AndroidTest/stability-info.json",
),🤖 Prompt for AI Agents |
||
| outputDir.set(extension.stabilityValidation.outputDir) | ||
| ignoredPackages.set(extension.stabilityValidation.ignoredPackages) | ||
|
|
@@ -175,7 +200,17 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| ) { | ||
| projectName.set(target.name) | ||
| stabilityInputFiles.from( | ||
| target.layout.buildDirectory.file("stability/stability-info.json"), | ||
| target.layout.buildDirectory.file("stability/${variant.name}/stability-info.json"), | ||
| ) | ||
| stabilityInputFiles.from( | ||
| target.layout.buildDirectory.file( | ||
| "stability/${variant.name}UnitTest/stability-info.json", | ||
| ), | ||
| ) | ||
| stabilityInputFiles.from( | ||
| target.layout.buildDirectory.file( | ||
| "stability/${variant.name}AndroidTest/stability-info.json", | ||
| ), | ||
| ) | ||
| stabilityReferenceFiles.from(extension.stabilityValidation.outputDir) | ||
| ignoredPackages.set(extension.stabilityValidation.ignoredPackages) | ||
|
|
@@ -212,6 +247,22 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| stabilityCheckTask, | ||
| ) | ||
| } | ||
|
|
||
| // Add output parameter to the Kotlin tasks to ensure it is compatible with the Build Cache | ||
| target.tasks.withType(KotlinCompile::class.java) | ||
| .named { | ||
| it.contains(variantNameUpperCase) && isKotlinTaskApplicable( | ||
| it, | ||
| extension.stabilityValidation.includeTests.get(), | ||
| ) | ||
| } | ||
| .configureEach { | ||
| val stabilityDir = | ||
| target.layout.buildDirectory | ||
| .dir(getKotlinTaskStabilityFolderName(project, name)) | ||
| .get() | ||
| outputs.dir(stabilityDir).optional(true) | ||
| } | ||
| } | ||
|
|
||
| target.afterEvaluate { | ||
|
|
@@ -266,10 +317,19 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| return project.provider { | ||
| val projectDependencies = collectProjectDependencies(project) | ||
|
|
||
| val stabilityFolderName = getKotlinTaskStabilityFolderName( | ||
| project, | ||
| kotlinCompilation.compileKotlinTaskName, | ||
| ) | ||
|
|
||
| // Write project dependencies to a file to avoid empty string issues with SubpluginOption | ||
| val stabilityDir = project.layout.buildDirectory.dir("stability").get().asFile | ||
| val stabilityDir = project.layout.buildDirectory.dir(stabilityFolderName).get().asFile | ||
| stabilityDir.mkdirs() | ||
| val dependenciesFile = java.io.File(stabilityDir, "project-dependencies.txt") | ||
|
|
||
| val variantlessStabilityDir = project.layout.buildDirectory.dir("stability").get().asFile | ||
| variantlessStabilityDir.mkdirs() | ||
|
|
||
| val dependenciesFile = java.io.File(variantlessStabilityDir, "project-dependencies.txt") | ||
| dependenciesFile.writeText(projectDependencies.joinToString("\n")) | ||
|
|
||
| listOf( | ||
|
|
@@ -289,6 +349,32 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin { | |
| } | ||
| } | ||
|
|
||
| private fun getKotlinTaskStabilityFolderName( | ||
| project: Project, | ||
| taskName: String, | ||
| ): String { | ||
| val variant = | ||
| if (project.extensions.findByType(AndroidComponentsExtension::class.java) != null) { | ||
| taskName | ||
| .removePrefix("compile") | ||
| .removeSuffix("Kotlin") | ||
| .replaceFirstChar { it.lowercase() } | ||
| } else { | ||
| if (taskName.contains("Test")) { | ||
| "test" | ||
| } else { | ||
| "" | ||
| } | ||
| } | ||
|
|
||
| val stabilityFolderName = if (variant.isBlank()) { | ||
| "stability" | ||
| } else { | ||
| "stability/$variant" | ||
| } | ||
| return stabilityFolderName | ||
| } | ||
|
|
||
| /** | ||
| * Add runtime to compiler plugin classpath. | ||
| * This ensures the compiler plugin can access runtime classes during compilation. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.