fix/ADFA-3380 template warnings#1147
Conversation
📝 Walkthrough
WalkthroughAdds propagation and UI display of template creation warnings: templates now collect warnings/errors during load/execution, results expose a Changes
Sequence DiagramssequenceDiagram
participant DF as TemplateDetailsFragment
participant MA as MainActivity
participant PHA as ProjectHandlerActivity
participant TP as TemplateProviderImpl
participant ZTR as ZipTemplateReader
participant ZRE as ZipRecipeExecutor
DF->>ZRE: execute(template)
ZRE->>ZRE: process entries, log warn/error (sets hasErrorsWarnings)
ZRE-->>DF: ProjectTemplateRecipeResultImpl(hasErrorsWarnings)
DF->>MA: openProject(dir, project, hasTemplateIssues=hasErrorsWarnings)
MA->>PHA: start Intent with HAS_TEMPLATE_ISSUES extra
PHA->>PHA: onCreate checks HAS_TEMPLATE_ISSUES
alt HAS_TEMPLATE_ISSUES == true
PHA->>PHA: flashError(msg_template_warnings)
end
TP->>ZTR: read(zipFile, warnings)
ZTR->>ZTR: append warnings on failures
ZTR-->>TP: templates (warnings populated)
TP->>TP: expose warnings to UI (TemplateListFragment)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt (1)
35-39:⚠️ Potential issue | 🟠 MajorReport a missing
ARCHIVE_JSONentry instead of silently returning.Line 38 still returns
emptyList()when the archive index is absent, so a malformed template ZIP bypasses the new warning/logging path and just looks like “no templates found.”Proposed fix
- val indexEntry = zip.getEntry(ARCHIVE_JSON) ?: return emptyList() + val indexEntry = zip.getEntry(ARCHIVE_JSON) + if (indexEntry == null) { + warnings.add("Missing template index $ARCHIVE_JSON in archive $zipFile") + log.error("Missing template index $ARCHIVE_JSON in archive $zipFile") + return emptyList() + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt` around lines 35 - 39, The code in ZipTemplateReader (ZipTemplateReader.kt) currently returns emptyList() when the ARCHIVE_JSON entry is missing, silently hiding malformed template ZIPs; update the logic in the try block where zip.getEntry(ARCHIVE_JSON) is checked so that instead of returning emptyList() it reports the missing entry (e.g., throw a specific exception or call the existing logger/error reporting path) with a clear message including the ZIP file name and ARCHIVE_JSON, ensuring callers can distinguish a malformed archive from "no templates found" (locate the check around zip.getEntry(ARCHIVE_JSON) and replace the silent return with a logged/exceptional path consistent with the module's error handling).
🧹 Nitpick comments (4)
templates-impl/src/main/java/com/itsaky/androidide/templates/impl/TemplateProviderImpl.kt (1)
47-47: Expose warnings as read-only API, not mutable state.
val warnings: MutableList<String>leaks internal mutability and creates tight coupling with consumers.🔒 Proposed encapsulation
- val warnings: MutableList<String> = mutableListOf() + private val warnings: MutableList<String> = mutableListOf() + val templateWarnings: List<String> + get() = warnings.toList()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/TemplateProviderImpl.kt` at line 47, The public property warnings is declared as a MutableList and leaks internal mutability; change TemplateProviderImpl to keep a private mutable backing field (e.g., _warnings or backingWarnings) and expose a read-only List<String> via a public val warnings: List<String> (or a getter returning the backing list), and update any internal code that mutates warnings to use the private backing field instead so consumers cannot modify internal state.app/src/main/java/com/itsaky/androidide/activities/MainActivity.kt (1)
403-430: Extract intent extra keys into shared constants.
"HAS_TEMPLATE_ISSUES"and"PROJECT_PATH"are string literals; centralizing them avoids key drift between launcher and receiver.♻️ Proposed refactor
+companion object { + const val EXTRA_PROJECT_PATH = "PROJECT_PATH" + const val EXTRA_HAS_TEMPLATE_ISSUES = "HAS_TEMPLATE_ISSUES" +} ... - putExtra("PROJECT_PATH", root.absolutePath) + putExtra(EXTRA_PROJECT_PATH, root.absolutePath) if (hasTemplateIssues) { - putExtra("HAS_TEMPLATE_ISSUES", true) + putExtra(EXTRA_HAS_TEMPLATE_ISSUES, true) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/com/itsaky/androidide/activities/MainActivity.kt` around lines 403 - 430, The openProject function uses string literals "PROJECT_PATH" and "HAS_TEMPLATE_ISSUES" for intent extras; extract these into shared constants (e.g., add public const val PROJECT_PATH and HAS_TEMPLATE_ISSUES in EditorActivityKt's companion object or a shared Constants object) and replace the literal usages in openProject (Intent.apply putExtra calls) with the new constants; also update any recipient code (EditorActivityKt reading intent extras) to use the same constants so keys are centralized and type-safe.templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt (1)
119-162: Narrow the new entry-processing catch blocks.The added
catch (e: Exception)handlers around template read/parse/evaluate/write/copy will also hide unrelated executor bugs behind warning logs. Limit each site to the expectedPebbleException/I/O failures and let unexpected exceptions surface. Based on learnings: in Kotlin files across this project, prefer narrow exception handling over a broadcatch (e: Exception); this aligns with fail-fast behavior during development.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt` around lines 119 - 162, The broad catch-all Exception handlers in ZipRecipeExecutor.kt around reading/parsing/evaluating/writing/copying template entries should be narrowed: replace catch (e: Exception) blocks with specific exceptions (e.g., IOException for file I/O operations, PebbleException for pebble parsing/evaluation) and allow unexpected exceptions to propagate (or rethrow) so they fail fast; specifically update the try around pebbleEngine.getTemplate(content) to only catch PebbleException, the template.evaluate(writer, identifiers) block to catch PebbleException, the outFile.writeText(...) and zip.getInputStream(...)/input.copyTo(output) blocks to catch IOException (or more specific java.io exceptions), and remove or rethrow the outer catch (e: Exception) that currently swallows all errors in processTemplate entry handling.templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt (1)
113-121: Narrow these catch-all loaders.Both new
catch (e: Exception)blocks will also downgrade unexpected loader bugs to recoverable warnings. Catch the ZIP/JSON failures you actually expect here and let the rest fail fast. Based on learnings: in Kotlin files across this project, prefer narrow exception handling over a broadcatch (e: Exception); this aligns with fail-fast behavior during development.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt` around lines 113 - 121, The two broad catch-all handlers in ZipTemplateReader (the blocks catching "Exception" around the per-entry template read that logs "Failed to load template at ${templateRef.path}" and the outer zip read that logs "Failed to read zip file $zipFile") should be narrowed: catch only the expected I/O and parsing exceptions (e.g., IOException/ZipException for archive/stream issues and JsonProcessingException/JsonParseException or JSONException/kotlinx.serialization exceptions for JSON/template parsing) and add the warning/log message there; any other unexpected exceptions should be rethrown so they fail fast. Update the catch clauses in the method(s) in ZipTemplateReader.kt that surround reading the zip and parsing template JSON (the blocks referencing templateRef.path and zipFile) to handle these specific exception types and keep the existing warnings/logging for those cases, letting other exceptions propagate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/main/java/com/itsaky/androidide/fragments/TemplateListFragment.kt`:
- Around line 120-123: The cast of provider to TemplateProviderImpl is unsafe
and can throw ClassCastException; change the access to warnings to use a safe
cast or type check: obtain provider via ITemplateProvider.getInstance(reload =
true), then check if provider is TemplateProviderImpl (or use a safe cast with
"as?" equivalent) and read (TemplateProviderImpl).warnings only when available,
otherwise use a sensible fallback (e.g., empty warnings list) so getTemplates()
and the UI don't crash; update the code that references provider/warnings (the
provider variable, ITemplateProvider.getInstance and
TemplateProviderImpl.warnings) accordingly.
In `@resources/src/main/res/values/strings.xml`:
- Line 1019: Remove the leading newline characters from the string resource
named msg_template_warnings so the flash message doesn't start with blank lines;
update the value of msg_template_warnings to begin directly with "Project
creation finished with warnings/errors. Open IDE Logs for details." (keep the
rest of the text unchanged) to preserve readability.
In `@templates-api/src/main/java/com/itsaky/androidide/templates/template.kt`:
- Around line 61-63: The interface ProjectTemplateRecipeResult exposes an
abstract val hasErrorsWarnings which forces all implementers to immediately
provide an implementation; change it to provide a default getter (e.g. val
hasErrorsWarnings: Boolean get() = false) so the interface supplies a sensible
default and preserves API/binary compatibility for external implementers of
ProjectTemplateRecipeResult (which extends
TemplateRecipeResultWithData<ProjectTemplateData>).
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt`:
- Around line 133-146: The current code always calls
outFile.writeText(writer.toString(), Charsets.UTF_8) even when
template.evaluate(...) failed and only logged an error; change the flow so the
file is not written when evaluation throws: for example, in the evaluate block
(where template.evaluate(writer, identifiers) is called and
PebbleException/Exception are caught) stop further processing on error (either
rethrow, return/continue the enclosing loop, or set a success flag) and only
call outFile.writeText(...) if evaluation succeeded; refer to template.evaluate,
the writer StringWriter, the caught PebbleException/Exception handlers,
entry.name and outFile.writeText to locate and implement this control-flow fix.
---
Outside diff comments:
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt`:
- Around line 35-39: The code in ZipTemplateReader (ZipTemplateReader.kt)
currently returns emptyList() when the ARCHIVE_JSON entry is missing, silently
hiding malformed template ZIPs; update the logic in the try block where
zip.getEntry(ARCHIVE_JSON) is checked so that instead of returning emptyList()
it reports the missing entry (e.g., throw a specific exception or call the
existing logger/error reporting path) with a clear message including the ZIP
file name and ARCHIVE_JSON, ensuring callers can distinguish a malformed archive
from "no templates found" (locate the check around zip.getEntry(ARCHIVE_JSON)
and replace the silent return with a logged/exceptional path consistent with the
module's error handling).
---
Nitpick comments:
In `@app/src/main/java/com/itsaky/androidide/activities/MainActivity.kt`:
- Around line 403-430: The openProject function uses string literals
"PROJECT_PATH" and "HAS_TEMPLATE_ISSUES" for intent extras; extract these into
shared constants (e.g., add public const val PROJECT_PATH and
HAS_TEMPLATE_ISSUES in EditorActivityKt's companion object or a shared Constants
object) and replace the literal usages in openProject (Intent.apply putExtra
calls) with the new constants; also update any recipient code (EditorActivityKt
reading intent extras) to use the same constants so keys are centralized and
type-safe.
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/TemplateProviderImpl.kt`:
- Line 47: The public property warnings is declared as a MutableList and leaks
internal mutability; change TemplateProviderImpl to keep a private mutable
backing field (e.g., _warnings or backingWarnings) and expose a read-only
List<String> via a public val warnings: List<String> (or a getter returning the
backing list), and update any internal code that mutates warnings to use the
private backing field instead so consumers cannot modify internal state.
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt`:
- Around line 119-162: The broad catch-all Exception handlers in
ZipRecipeExecutor.kt around reading/parsing/evaluating/writing/copying template
entries should be narrowed: replace catch (e: Exception) blocks with specific
exceptions (e.g., IOException for file I/O operations, PebbleException for
pebble parsing/evaluation) and allow unexpected exceptions to propagate (or
rethrow) so they fail fast; specifically update the try around
pebbleEngine.getTemplate(content) to only catch PebbleException, the
template.evaluate(writer, identifiers) block to catch PebbleException, the
outFile.writeText(...) and zip.getInputStream(...)/input.copyTo(output) blocks
to catch IOException (or more specific java.io exceptions), and remove or
rethrow the outer catch (e: Exception) that currently swallows all errors in
processTemplate entry handling.
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt`:
- Around line 113-121: The two broad catch-all handlers in ZipTemplateReader
(the blocks catching "Exception" around the per-entry template read that logs
"Failed to load template at ${templateRef.path}" and the outer zip read that
logs "Failed to read zip file $zipFile") should be narrowed: catch only the
expected I/O and parsing exceptions (e.g., IOException/ZipException for
archive/stream issues and JsonProcessingException/JsonParseException or
JSONException/kotlinx.serialization exceptions for JSON/template parsing) and
add the warning/log message there; any other unexpected exceptions should be
rethrown so they fail fast. Update the catch clauses in the method(s) in
ZipTemplateReader.kt that surround reading the zip and parsing template JSON
(the blocks referencing templateRef.path and zipFile) to handle these specific
exception types and keep the existing warnings/logging for those cases, letting
other exceptions propagate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8e593f73-abaa-4c81-ae87-1ebe5211b9cc
📒 Files selected for processing (10)
app/src/main/java/com/itsaky/androidide/activities/MainActivity.ktapp/src/main/java/com/itsaky/androidide/activities/editor/ProjectHandlerActivity.ktapp/src/main/java/com/itsaky/androidide/fragments/TemplateDetailsFragment.ktapp/src/main/java/com/itsaky/androidide/fragments/TemplateListFragment.ktresources/src/main/res/values/strings.xmltemplates-api/src/main/java/com/itsaky/androidide/templates/template.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/TemplateProviderImpl.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/base/results.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipTemplateReader.kt
app/src/main/java/com/itsaky/androidide/fragments/TemplateListFragment.kt
Show resolved
Hide resolved
templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt (1)
293-311:⚠️ Potential issue | 🟠 MajorCross-platform bug: ZIP entry paths use
/, notFile.separator.ZIP archives always use forward slash (
/) as the path separator, regardless of the operating system. On Windows,File.separatoris\, soentryName.split(File.separator)will fail to split the entry name correctly.Note that lines 85-87 already correctly use
/for ZIP entry path checks. The joining at line 310 withFile.separatoris appropriate for constructing file system paths, but the split on input needs to use/.Proposed fix
private fun filterAndNormalizeZipEntry( entryName: String, flags: Map<String, Boolean> ): String? { - val parts = entryName.split(File.separator).filter { it.isNotEmpty() } + val parts = entryName.split("/").filter { it.isNotEmpty() } if (parts.isEmpty()) return null val normalizedParts = mutableListOf<String>() for (part in parts) { when (flags[part]) { null -> normalizedParts.add(part) true -> { } false -> return null } } return normalizedParts.joinToString(File.separator) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt` around lines 293 - 311, The split logic in filterAndNormalizeZipEntry is incorrect for ZIP entries: change entryName.split(File.separator) to entryName.split("/") (ZIP uses forward slashes always), keep the existing filter { it.isNotEmpty() } and continue to join with File.separator when returning the normalized filesystem path; update only the split call in the filterAndNormalizeZipEntry function so path checks and normalization work cross-platform.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt`:
- Around line 293-311: The split logic in filterAndNormalizeZipEntry is
incorrect for ZIP entries: change entryName.split(File.separator) to
entryName.split("/") (ZIP uses forward slashes always), keep the existing filter
{ it.isNotEmpty() } and continue to join with File.separator when returning the
normalized filesystem path; update only the split call in the
filterAndNormalizeZipEntry function so path checks and normalization work
cross-platform.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 086eb611-209d-4a14-996b-10ca806be4ca
📒 Files selected for processing (3)
app/src/main/java/com/itsaky/androidide/fragments/TemplateListFragment.kttemplates-api/src/main/java/com/itsaky/androidide/templates/template.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/zip/ZipRecipeExecutor.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- app/src/main/java/com/itsaky/androidide/fragments/TemplateListFragment.kt
Show detailed warnings and errors in IDE Logs tab during template generation