i18n: let a plugin that cannot rename downgrade the namespace check to a warning - #16200
i18n: let a plugin that cannot rename downgrade the namespace check to a warning#16200codeconsole wants to merge 1 commit into
Conversation
…to a warning
The namespace check exists because Spring resolves a base name to the first
match on the classpath instead of merging, so two artifacts shipping the same
base name shadow one another with nothing at runtime to say which won. Failing
the plugin's own build is the right default: it puts the error in front of the
only person who can rename the bundle.
It has no escape hatch, though, and grails { i18n { basenames } } is not one --
declared base names are folded into the index before the check runs, so a
plugin cannot declare its way past it. That leaves a plugin that genuinely
cannot rename -- a base name that is part of a published contract, or a bundle
vendored from somewhere else -- with `-x generateI18nDescriptor`, which ships no
descriptor at all and so drops the plugin's messages entirely, or a fork.
Add grails { i18n { enforceNamespace = false } }. It downgrades the same
diagnosis to a build warning and writes the descriptor as it stands; the
default is unchanged. The wording is identical either way, because what is
wrong and how to fix it do not change with the severity, and both the message
and the upgrade guide are explicit that this silences the build rather than the
collision.
🚨 TestLens detected 9 failed tests 🚨Here is what you can do:
Test SummaryCI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1) > :grails-data-mongodb-core:test
🏷️ Commit: baffa9d Test FailuresMongoTransactionSpec > test a REQUIRES_NEW inner transaction commits independently of a rolled back outer transaction (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test a committed transaction persists all writes atomically (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test a findOneAndDelete via the MongoEntity API participates in the transaction (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test a per-transaction timeout is rejected rather than silently ignored (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test a rolled back transaction discards a native Long id entity (id generation is non-transactional) (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test a rolled back transaction discards all writes on the server (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test native Long identifier generation works for entities committed in a transaction (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test read-your-writes within an active transaction (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))MongoTransactionSpec > test writes across multiple collections roll back together (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / Build Grails with Groovy snapshot (shard 1))Rerun ControlsNote Checks are currently running using the configuration below. Select tests to mute in this pull request: 🔲 MongoTransactionSpec > test a REQUIRES_NEW inner transaction commits independently of a rolled back outer transaction Reuse successful test results: 🔲 ♻️ Only rerun the tests that failed or were muted before Click the checkbox to trigger a rerun: 🔲 Rerun jobs Learn more about TestLens at testlens.app/docs. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## 8.0.x #16200 +/- ##
==================================================
+ Coverage 54.0157% 54.0173% +0.0016%
- Complexity 20170 20174 +4
==================================================
Files 2103 2103
Lines 100643 100653 +10
Branches 17822 17824 +2
==================================================
+ Hits 54363 54370 +7
- Misses 38522 38524 +2
- Partials 7758 7759 +1
🚀 New features to boost your workflow:
|
|
Withdrawing this — the premise doesn't hold up. I justified the opt-out with plugins that "cannot rename": a base name that is part of a published contract, or a vendored third-party bundle. Neither survives scrutiny. Message codes are the contract and a rename doesn't touch them; nothing consumes a plugin's base name (Grails 7 discovered bundles by scanning and never read the name, and applications override messages by code in their own bundle). A vendored bundle is vendored by contents, not by file name, so renaming it costs nothing. The case that prompted this was a Spring Security fork still shipping the upstream plugin's base name. The check was right to catch it — a genuine collision — and the fix was one It also cuts against the reason the check fails hard in the first place: a warning in a plugin's own build is read by nobody, and the damage lands in someone else's application later. Not worth adding speculative configuration surface to a feature this new. Happy to revisit if someone turns up with a bundle they genuinely cannot rename. |
Follow-up to #16102.
The gap
generateI18nDescriptorfails a plugin build when a base name sits outside the plugin's namespace. That default is right, and this PR does not change it — Spring resolves a base name to the first match on the classpath rather than merging, so two artifacts shipping the same base name shadow one another with nothing at runtime to say which won. Failing the plugin's own build puts the error in front of the only person who can rename the bundle.What it lacks is an escape hatch, and
grails { i18n { basenames } }is not one: declared base names are folded into the index beforevalidatePluginNamespaceruns, so a plugin cannot declare its way past the check.That leaves a plugin that genuinely cannot rename — a base name that is part of a published contract, or a bundle vendored from somewhere else — with two options:
-x generateI18nDescriptor, which ships no descriptor at all and therefore drops the plugin's messages entirely, orThe change
grails { i18n { enforceNamespace = false } }Downgrades the same diagnosis to a build warning and writes the descriptor as it stands. Default unchanged (
true).The wording is identical whether it throws or warns — what is wrong and how to fix it do not depend on the severity — so
validatePluginNamespacebecomesdescribeNamespaceViolation, returning the message ornull, and the caller decides. Both the message and the upgrade guide say plainly that the opt-out silences the build, not the collision.Tests
GenerateI18nDescriptorTaskSpec— the check is on by convention;enforceNamespace = falserecords the bundle and does not throw; the message names the opt-out and its caveat.I18nDescriptorFunctionalSpec+ a newi18n-descriptor-plugin-namespace-offtest project — the same colliding bundle asi18n-descriptor-plugin-collision, plus thei18nblock, exercised end to end throughprocessResources: the build succeeds, still reports the collision, and the descriptor recordsbasenames=messages.:grails-gradle-plugins:checkpasses (includingvalidatePlugins), andratpasses.Context
Found while upgrading an app to 8.0.0-M6. Its Spring Security fork shipped the base name it inherited from the upstream plugin — a real collision, and the check caught it, so this is not a complaint about the rule. Renaming was the right fix there. The opt-out is for the cases where it isn't available.