Skip to content

ci(publish): publish the compiler plugin only when it changes - #45

Open
lukmccall wants to merge 1 commit into
mainfrom
ci/publish-compiler-plugin-only-when-changed
Open

lukmccall wants to merge 1 commit into
mainfrom
ci/publish-compiler-plugin-only-when-changed

Conversation

@lukmccall

@lukmccall lukmccall commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Maven Central now caps how many files an organization publishes per month, and every file counts: each artifact goes up with its .asc, .md5 and .sha1. A release of this repo uploads about 268 files. 220 of them are the compiler plugin (11 Kotlin builds × jar/sources/javadoc/module/pom × 4), and it is uploaded even when it hasn't changed. 0.1.2, 0.1.4, 0.2.1, 0.2.2 and 0.2.6 all re-uploaded an identical plugin.

What

  • A separate version for the compiler plugin. gradle/libs.versions.toml gets a compiler-plugin version, starting at 0.2.7 (what's on Central now). :compiler-plugin publishes as <compiler-plugin>-<kotlin>, and the Gradle plugin resolves that version through a new BuildConfig.KOTLIN_PLUGIN_VERSION, which replaces EXPO_MODULES_V2_VERSION.
  • Each stage-compiler matrix entry checks Central before staging. It builds the jar, and scripts/compare-with-maven-central.sh compares its entries with the jar Central holds at the same coordinates:
    • not on Central yet: staged and uploaded as before;
    • same contents: skipped, with a notice annotation;
    • different contents: the release fails before anything is uploaded, because the plugin changed without a version bump.

The comparison works because the build is reproducible. Rebuilding the plugin locally for every Kotlin release in gradle/kotlin-versions.txt gives jars identical, entry by entry, to the 0.2.7-* jars on Central.

Is an older plugin safe with a newer :api?

The plugin doesn't bundle :api. It finds :api symbols by name (Identifiers.kt) on the consumer's classpath, so the only mix a consumer can get is an older plugin with a newer :api. CI already tests exactly that mix: the box tests, :api and :react compile with the plugin built from the current source. If that source builds the same bytes as the published plugin, the shipped pairing has been tested. An :api change that needs a plugin change (like #42) changes the plugin bytes, and the release then fails until compiler-plugin is bumped.

Releasing after this

  • Plugin unchanged: bump expo-modules-v2 only. The release uploads 48 files.
  • Plugin changed: also set compiler-plugin to the new version. If you forget, the publish workflow fails and says so.

One known edge case: repo1 can take ~30 min to serve a new upload. A release right after one that bumped the plugin may not find it there yet and try to upload it again. Central rejects the duplicate and the deployment fails as a whole; re-running later fixes it.

Testing

  • Ran the new workflow step locally against Central for all 11 Kotlin releases: every one reports published (it would be skipped).
  • Bumped compiler-plugin to 0.2.8: unpublished (it would be staged).
  • Changed a constant in the plugin without a bump: fails with the differing classes and the "bump compiler-plugin" error.
  • Unreachable repository: fails without staging anything.
  • :gradle-plugin:build passes; the generated KOTLIN_PLUGIN_VERSION is 0.2.7.
  • The publish workflow itself has not run in Actions yet; the next release is its first real run.

Same change in kolibri: expo/kolibri#5

🤖 Generated with Claude Code

The compiler plugin gets its own version in the catalog (`compiler-plugin`), which the Gradle
plugin resolves. Each publish matrix entry builds the plugin, compares it with the jar Maven Central
holds under that version, and skips the upload when the contents match. A plugin that changed without
a version bump fails the release before anything is uploaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

libexpo-modules-v2.so size (arm64-v8a, stripped)

No change

Base This PR Change
File size 351,880 B (343.6 KiB) 351,880 B (343.6 KiB) 0
Exported symbols 20 20 0
Sections (0 changed)
Section Base This PR Change
.text 251,868 251,868 0
.eh_frame 34,692 34,692 0
.rodata 19,171 19,171 0
.gcc_except_table 16,912 16,912 0
.eh_frame_hdr 5,156 5,156 0
.dynstr 5,106 5,106 0
.data.rel.ro 4,328 4,328 0
.dynsym 3,480 3,480 0
(headers and padding) 2,333 2,333 0
.rela.dyn 2,329 2,329 0
.rela.plt 2,088 2,088 0
.plt 1,424 1,424 0
.got.plt 720 720 0
.dynamic 464 464 0
.data 328 328 0
.gnu.version 290 290 0
.got 280 280 0
.shstrtab 275 275 0
.comment 204 204 0
.note.android.ident 152 152 0
.gnu.hash 148 148 0
.gnu.version_r 64 64 0
.note.gnu.build-id 36 36 0
.fini_array 16 16 0
.init_array 16 16 0

Kotlin code size (:react, dexed by D8, not shrunk)

No change

Base This PR Change
Dex size 286,352 B (279.6 KiB) 286,352 B (279.6 KiB) 0
Class files 730,695 B (713.6 KiB) 730,695 B (713.6 KiB) 0
Classes 198 198 0
Methods 1,791 1,791 0
Dex sections (0 changed)
Section Base This PR Change
string_data 118,656 118,656 0
code 71,186 71,186 0
annotations 23,624 23,624 0
method_ids 14,328 14,328 0
class_data 10,054 10,054 0
string_ids 9,936 9,936 0
proto_ids 6,996 6,996 0
class_defs 6,912 6,912 0
debug_info 6,122 6,122 0
annotations_directories 5,696 5,696 0
annotation_sets 4,744 4,744 0
type_lists 3,100 3,100 0
field_ids 3,032 3,032 0
type_ids 1,540 1,540 0
map_list 208 208 0
header 112 112 0
encoded_arrays 106 106 0
Class files by package (0 changed)
Package Base This PR Change Classes
io.github.expo.modules.v2.converters 213,544 213,544 0 41
io.github.expo.modules.v2.types 123,662 123,662 0 43
io.github.expo.modules.v2.async 58,113 58,113 0 16
io.github.expo.modules.v2.modules 40,479 40,479 0 11
io.github.expo.modules.v2.jsi 37,357 37,357 0 9
io.github.expo.modules.v2.records 36,048 36,048 0 10
io.github.expo.modules.v2.args 34,500 34,500 0 8
io.github.expo.modules.v2 31,576 31,576 0 19
io.github.expo.modules.v2.binary 31,384 31,384 0 6
io.github.expo.modules.v2.sharedobjects 22,412 22,412 0 4
io.github.expo.modules.v2.events 21,878 21,878 0 4
io.github.expo.modules.v2.react 18,981 18,981 0 6
io.github.expo.modules.v2.cache 16,655 16,655 0 6
io.github.expo.modules.v2.records.writers 16,026 16,026 0 3
io.github.expo.modules.v2.records.readers 15,795 15,795 0 3
io.github.expo.modules.v2.logging 4,635 4,635 0 4
io.github.expo.modules.v2.loader 2,535 2,535 0 1
io.github.expo.modules.v2.errors 2,101 2,101 0 1
io.github.expo.modules.v2.jni 1,563 1,563 0 1
io.github.expo.modules.v2.core 1,451 1,451 0 2

Base: main at c5c8a61. This PR: 9d9e409, merged into the base.

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