Repository navigation
feat(android): org.nativescript:gradle-api, Gradle facts file and opt-in read-only node_modules - #6175
Draft
edusperoni wants to merge 2 commits into
Draft
feat(android): org.nativescript:gradle-api, Gradle facts file and opt-in read-only node_modules#6175edusperoni wants to merge 2 commits into
edusperoni wants to merge 2 commits into
Conversation
… for plugins A Java Gradle library (plugin id `org.nativescript.api`, extension `nativescript`) that plugins load from their buildscript.gradle and call from include.gradle instead of building paths into node_modules or the CLI's output folders. It reads the facts file the CLI writes (platforms/android/nativescript-gradle.json, schema in gradle-api/schema) and falls back to the rules CLIs up to 9.1 use when there is none, or when it no longer matches dependencies.json. Compiled for Java 11 against the Gradle 7.5 API; functional tests cover Gradle 7.5.1, 8.14.3 and 9.8.1 and run the CLI's plugin-build template with AGP. Adds the gradle_api workflow: tests on changes, publishing to Maven Central on gradle-api-v* tags from the protected maven-central environment.
…read-only node_modules - `ns prepare android` writes platforms/android/nativescript-gradle.json next to dependencies.json (project dirs and every native plugin's package dir, native dir and aar, paths relative to the file, plus the hash of dependencies.json) and passes -Pnativescript.factsFile to app and plugin Gradle builds. org.nativescript:gradle-api reads it. - Plugins whose short names clash (@foo/plugin-x and @bar/plugin-x) get scope-qualified aar names, temp build dirs and namespace fallbacks. Names that don't clash are unchanged. An aar left under a plugin's previous name is deleted when it is the CLI's own output, otherwise prepare stops. - `android.readOnlyNodeModules` in nativescript.config: plugins' Android files and package.json are mirrored into platforms/android/.ns-plugins, aars are built and include.gradle is migrated there, dependencies.json points at the mirrors, and plugin aar builds also apply the plugin's own buildscript.gradle and the gradle-api library.
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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 |
Contributor
|
Given the config option is interim (potential to make default in future), the naming is probably ok if a description describes clearly why the option is available. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Checklist
What is the current behavior?
Plugins guess paths. A plugin's
platforms/android/include.gradlefinds what it needs bybuilding paths itself. From published plugins:
Each one bakes in something the CLI should be free to change: where
node_modulesis, where the CLIputs a plugin's built
.aar, how many../reach the project root, whattempBuildmeans.That's why #5937 (move built aars out of
node_modules) broke plugins and stalled.The CLI writes into
node_modules. Exactly two places do (I audited every write):.aarof each plugin with Android sources goes tonode_modules/<plugin>/platforms/android/<name>.aar;include.gradleis rewritten in place to stripproductFlavors.(iOS already writes its generated files to
platforms/ios/.plugins.)Plugin aar names clash. The aar name drops the npm scope, so
@foo/plugin-xand@bar/plugin-xboth build
plugin_x.aar, shareplatforms/tempPlugin/plugin_x, and get the same namespacefallback
org.nativescript.plugin_x. Which one the app ends up linking depends on build order.Android Studio builds lose App_Resources settings. The app and App_Resources locations are
passed only as
-PappPath/-PappResourcesPathon the CLI's own Gradle calls. Buildingplatforms/androidfrom Android Studio falls back toapp/App_Resources, so a project with anotherlayout silently skips
App_Resources/Android/app.gradle,before-plugins.gradle,gradle.propertiesand
libs/.What is the new behavior?
Four pieces. Nothing changes for an existing project unless it opts in, except where noted.
1.
org.nativescript:gradle-api: a Gradle library plugins call instead of guessingNew Java library in
gradle-api/, published to Maven Central with its own version.Same model as androidx: the plugin carries the library, so an updated plugin keeps building for
someone on CLI 9.1.
apiLevel,has(capability),pluginBuild,self,isBuildingPlugin(name),projectDir,appDir,appResourcesDir,plugin(name)/findPlugin(name)→ name,packageDir,nativeDir,artifacts,aarName,aar,options, andresolvePackage(name)/findPackage(name). Full reference and recipes:gradle-api/README.md.dependencies.json,USER_PROJECT_ROOT,-PappPath,tempBuild.highest version, so the library only ever grows. Plugins pin the lowest version they need.
runtime uses. A plugin that adopts the library therefore needs runtime 8.4+ (Gradle 7.5 /
AGP 7.3); plugins still supporting older runtimes keep their current Gradle code for those.
.aarbuild. There, only thedependencies {}andrepositories {}blocks of
include.gradlerun: the CLI copies them out of the file. On older CLIs the libraryisn't loaded there. The README shows the guarded pattern that works everywhere:
dependencies { def ns = project.extensions.findByName("nativescript") if (ns != null && ns.pluginBuild) { compileOnly ns.plugin("@nativescript/core").artifacts } else if (project.hasProperty("tempBuild")) { compileOnly fileTree(dir: "$USER_PROJECT_ROOT/node_modules/@nativescript/core/platforms/android", include: "*.aar") } }2. Facts file:
platforms/android/nativescript-gradle.json(always written)Written by
ns prepare androidright afterdependencies.json, before any plugin is built. Schema:gradle-api/schema/nativescript-gradle.schema.json.native dir, aar name and location, and native dependencies. Paths are relative to the file, with
forward slashes. The file is only rewritten when its content changes.
-Pnativescript.factsFile=<path>goes to app builds and plugin builds. Thelibrary also finds the file next to the app build, so Android Studio builds get the same answers
without the CLI's flags.
dependenciesJson.sha256. An older CLI (after a downgrade)rewrites
dependencies.jsonbut not this file. The library sees the mismatch, warns, and uses thefallback rules.
capabilities(empty in v1) lets readers tell "not set" from "this CLI doesn't know about it";optionsper plugin is reserved for per-plugin settings fromnativescript.configlater.3. Unique aar names (always on, only affects projects with a clash)
A plugin whose short name is unique keeps it, so every project without a clash builds exactly as
before (
dependencies.jsonbyte-identical, asserted in tests). When names clash, scoped plugins get<scope>_<name>, for examplefoo_plugin_x. That name is used for the aar, the temp build dir andthe namespace fallback.
A clash that can't be resolved, such as
@foo/plugin-xvs@foo/plugin_x, now fails prepare witha clear message instead of building one of them.
An old aar left behind under the previous name would add duplicate classes, so:
ns clean".Projects with a clash are linking only one of the two plugins today. Both plugins used to build into
the same temp folder, so on the first prepare after upgrading, a clashing project usually has to run
ns cleanonce.4. Opt-in: keep
node_modulesread-onlyplatforms/androidand itspackage.jsonintoplatforms/android/.ns-plugins/<name>/.productFlavorsrewrite on the copy.dependencies.jsonpoints at the copy.plugins only through
dependencies.json'sdirectory, and so does Android Studio. No runtimechange is needed.
removes files deleted upstream, and never deletes the CLI's own outputs;
.aarbuilds: the CLI also applies the plugin's ownbuildscript.gradlein its own.aarbuild, and applies the library there when that script puts it on the classpath.buildscript.gradlefiles; they only add classpathentries and repositories.
Without the key, behaviour is today's plus pieces 2 and 3. Turning it off again deletes
.ns-plugins. After turning it on, reinstallnode_modulesonce to get rid of.aarfiles earlierbuilds left there.
Compatibility
readOnlyNodeModules.aarbuildbuildscript.gradlealso runs.aarbuildHow Martin's proposals fit later
These become additions to the facts file and API, with no breaking changes:
plugins[].options→nativescript.plugin(name).optionsbuild.abisfact, guarded by a capabilityaarSuffix(#6132)../pluginstempBuild(#5691)nativescript.pluginBuild;tempBuildkeeps being setTests
npm test, 2144 passed):order independence;
dependencies.jsonbyte-identical without the opt-in;-Pflags;include.gradleblocks the Java tests run.cd gradle-api && ./gradlew check, 188 unit + 15 functional, needs JDK 17):to: buildscript, include.gradle applied from inside a closure). They load the library from alocal Maven repo, the way a real plugin does, on Gradle 7.5.1 / 8.14.3 / 9.8.1, with and without
facts, and with stale facts.
vendor/gradle-pluginverbatim with AGP 8.12.1. They prove the guardedpattern works without the library (CLI 9.1) and with it (opt-in).
.github/workflows/gradle_api.yml.Not in this PR
readOnlyNodeModulesthe default. That's a later major, once plugins had time to adopt.Open questions
org.nativescriptnamespace (@triniwiz published
org.nativescript:canvasthere), a release signing key, and aCentral Portal token. The four secrets go in a protected
maven-centralenvironment; seeReleasing.
vendor/gradle-plugin/gradle/wrapper/gradle-wrapper.jar(sha256414142e6…fe0a3) is a Gradle 3.3wrapper from 2017, and Gradle doesn't publish checksums for wrappers that old.
now.
gradle-api/uses) ina separate PR, since that touches every plugin build for every user.
buildscript.gradlerun in its.aarbuild whenever a facts fileexists, instead of only with the opt-in? That would let plugins drop the old-CLI branch sooner,
at the cost of the behaviour change above for everyone on 9.2.
<short>.aarnext to its sources and then gets renamed by aclash makes prepare stop, because the CLI didn't build that file. Accept that (those projects
already link duplicate classes), or leave files the CLI didn't build alone?
hostProjectPathis on another Windows drive, the facts file can't hold a relative path.runtime.versionin the facts is the version declared in package.json, which can be a range.templates don't support the configuration cache anyway.
:appbuild readsnativescriptDependencies/PLATFORMS_ANDROIDthrough the parent project. Gradle 9.8 deprecates that and Gradle 10 will make it an error; that
needs a fix in NativeScript/android.