Skip to content

ADFA-3169: Auto-generate unique plugin versions at build time#1104

Open
Daniel-ADFA wants to merge 1 commit intostagefrom
ADFA-3169
Open

ADFA-3169: Auto-generate unique plugin versions at build time#1104
Daniel-ADFA wants to merge 1 commit intostagefrom
ADFA-3169

Conversation

@Daniel-ADFA
Copy link
Contributor

No description provided.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2026

📝 Walkthrough

Release Notes: Auto-generate Unique Plugin Versions at Build Time

Features

  • Automatic plugin version generation: Plugins now have versions auto-generated at build time with format <baseVersion>-<variantName>.<timestamp> (timestamp format: yyyyMMddHHmmss)
  • Manual version override: Added optional pluginVersion Gradle property in PluginBuilderExtension to allow explicit version specification
  • Dynamic manifest placeholder injection: Plugin version is resolved through manifest placeholders (${pluginVersion}) instead of hardcoded values
  • Truncated version display: Plugin list UI now displays long version strings with ellipsis (e.g., v1.0.0...) when more than 3 version segments are present

Changes

  • Updated all plugin manifests (apk-viewer-plugin, keystore-generator-plugin, markdown-preview-plugin) to use ${pluginVersion} placeholder
  • Modified PluginBuilder build logic to resolve and inject versions into variant manifest placeholders
  • Updated plugin template generator to emit ${pluginVersion} placeholder in generated manifests

⚠️ Risks & Best Practices Concerns

  • Non-deterministic builds: Version generation includes LocalDateTime.now() timestamp, making builds non-deterministic. Identical source code will produce different APKs on different builds, violating reproducible build principles
  • Timezone inconsistency: LocalDateTime.now() is timezone-aware but not explicitly managed; builds may produce different timestamps across machines in different time zones
  • Manifest placeholder fallback: If build system fails to inject pluginVersion into manifest, plugins will have literal "${pluginVersion}" as their version string with no error/warning
  • Version format not validated: Manually-specified pluginVersion property has no validation for format compliance
  • UI truncation ambiguity: Version string truncation with "..." may prevent users from identifying exact version numbers, potentially causing issues with bug reporting and compatibility tracking

Walkthrough

The pull request implements a build-time plugin versioning system by replacing hardcoded version strings in plugin manifests with a ${pluginVersion} placeholder. A new PluginBuilder variant callback computes versions dynamically—either from explicit configuration or derived from app version with build variant and timestamp suffixes—then injects resolved values into manifest placeholders at build time.

Changes

Cohort / File(s) Summary
Plugin Manifest Updates
apk-viewer-plugin/src/main/AndroidManifest.xml, keystore-generator-plugin/src/main/AndroidManifest.xml, markdown-preview-plugin/src/main/AndroidManifest.xml
Updated plugin.version meta-data values from hardcoded version strings (1.0.2, 1.0.3, 1.0.0) to ${pluginVersion} placeholder for build-time resolution.
Plugin Builder Infrastructure
plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt, plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilderExtension.kt
Added pluginVersion Gradle property to extension; PluginBuilder now registers variant callback to compute resolved version (from config or derived from app version with variant and timestamp) and inject into manifest placeholders.
Plugin Template
templates-impl/src/main/java/com/itsaky/androidide/templates/impl/pluginProject/pluginManifest.kt
Updated generated plugin manifest template to emit ${pluginVersion} placeholder instead of direct version interpolation.
Plugin List Display
app/src/main/java/com/itsaky/androidide/adapters/PluginListAdapter.kt
Added version string truncation logic: displays first three dot-separated segments followed by ... for versions with more than 3 segments, otherwise displays full version.

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant BuildSys as Build System
    participant PluginBld as PluginBuilder
    participant Manifest as Manifest
    participant App as Runtime App

    Dev->>BuildSys: Configure pluginVersion or use defaults
    BuildSys->>PluginBld: Trigger onVariants callback
    PluginBld->>PluginBld: Resolve version from config or<br/>derive from app version +<br/>variant + timestamp
    PluginBld->>Manifest: Inject resolvedVersion into<br/>placeholder pluginVersion
    BuildSys->>Manifest: Generate APK with resolved values
    App->>Manifest: Read plugin.version meta-data
    App->>App: Format & display in PluginListAdapter
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • jomen-adfa
  • jatezzz
  • hal-eisen-adfa

Poem

🐰 Versions once static, now dance in the build,
Placeholders whisper where numbers once filled,
A timestamp, a variant, dynamically born—
Our plugins now versioned each build and each morn! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, making it impossible to assess whether it relates to the changeset. Add a description explaining the purpose and motivation for auto-generating plugin versions at build time, including how the placeholder mechanism works.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: implementing auto-generation of unique plugin versions at build time, which matches the changeset modifications to manifest placeholders and version resolution logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ADFA-3169

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can generate a title for your PR based on the changes with custom instructions.

Set the reviews.auto_title_instructions setting to generate a title for your PR based on the changes in the PR with custom instructions.

Copy link
Contributor

@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.

🧹 Nitpick comments (2)
plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt (2)

13-16: Consider using UTC for timestamp consistency across build environments.

LocalDateTime.now() uses the system's default timezone, which could produce different version strings for the same commit when built on machines in different timezones. Consider using Instant.now() or LocalDateTime.now(ZoneOffset.UTC) for reproducibility.

♻️ Suggested fix for timezone consistency
 companion object {
-    private val TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
+    private val TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
+        .withZone(java.time.ZoneOffset.UTC)
     private const val DEFAULT_VERSION = "1.0.0"
 }

And update the usage:

-val timestamp = LocalDateTime.now().format(TIMESTAMP_FORMATTER)
+val timestamp = java.time.Instant.now().let { TIMESTAMP_FORMATTER.format(it) }

Also applies to: 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt`
around lines 13 - 16, The timestamp uses the system default timezone (via
LocalDateTime.now()), causing non-reproducible version strings across machines;
update the timestamp generation to use UTC: either call
LocalDateTime.now(ZoneOffset.UTC) where the timestamp is created or switch to
Instant.now() and use a DateTimeFormatter withZone(ZoneOffset.UTC) so
TIMESTAMP_FORMATTER produces UTC timestamps consistently (update usages where
the timestamp is constructed, e.g., the code referencing TIMESTAMP_FORMATTER
around line 33).

53-54: Migrate project.buildDir to project.layout.buildDirectory for Gradle 8.3+ compatibility.

The buildDir property is deprecated as of Gradle 8.3 and will be removed in Gradle 10.0. Replace with layout.buildDirectory:

Example migration
// Before
val apkDir = File(project.buildDir, "outputs/apk/debug")

// After
val apkDir = project.layout.buildDirectory.dir("outputs/apk/debug").get().asFile

This applies to lines 53–54 (debug task) and 83–84 (release task).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt`
around lines 53 - 54, Replace uses of the deprecated project.buildDir in
PluginBuilder.kt for both debug and release task sections (the apkDir and
outputDir assignments) with the new ProjectLayout API: use
project.layout.buildDirectory with dir(...) and then obtain the File via
get().asFile; update the apkDir and outputDir initializations in the debug block
(symbols apkDir and outputDir) and likewise in the release block to use
project.layout.buildDirectory.dir(...).get().asFile instead of
File(project.buildDir, ...).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt`:
- Around line 13-16: The timestamp uses the system default timezone (via
LocalDateTime.now()), causing non-reproducible version strings across machines;
update the timestamp generation to use UTC: either call
LocalDateTime.now(ZoneOffset.UTC) where the timestamp is created or switch to
Instant.now() and use a DateTimeFormatter withZone(ZoneOffset.UTC) so
TIMESTAMP_FORMATTER produces UTC timestamps consistently (update usages where
the timestamp is constructed, e.g., the code referencing TIMESTAMP_FORMATTER
around line 33).
- Around line 53-54: Replace uses of the deprecated project.buildDir in
PluginBuilder.kt for both debug and release task sections (the apkDir and
outputDir assignments) with the new ProjectLayout API: use
project.layout.buildDirectory with dir(...) and then obtain the File via
get().asFile; update the apkDir and outputDir initializations in the debug block
(symbols apkDir and outputDir) and likewise in the release block to use
project.layout.buildDirectory.dir(...).get().asFile instead of
File(project.buildDir, ...).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2abdd090-5f9a-4b74-8650-bf777a478877

📥 Commits

Reviewing files that changed from the base of the PR and between 19e414c and 23e7daa.

📒 Files selected for processing (7)
  • apk-viewer-plugin/src/main/AndroidManifest.xml
  • app/src/main/java/com/itsaky/androidide/adapters/PluginListAdapter.kt
  • keystore-generator-plugin/src/main/AndroidManifest.xml
  • markdown-preview-plugin/src/main/AndroidManifest.xml
  • plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt
  • plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilderExtension.kt
  • templates-impl/src/main/java/com/itsaky/androidide/templates/impl/pluginProject/pluginManifest.kt

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.

1 participant