Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brownfield-gradle-plugin-source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@callstack/react-native-brownfield': patch
---

Expose the Brownfield Android Gradle Plugin source from the npm package for opt-in local patching.
51 changes: 51 additions & 0 deletions docs/docs/docs/getting-started/android.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,57 @@ react {
}
```

### Advanced: Load the Plugin from Node Modules

Use the source version only when you need to patch the Brownfield Gradle Plugin locally, for example with `patch-package`.

Add the included build to the top of `android/settings.gradle.kts`:

```kotlin
pluginManagement {
includeBuild(
File(
providers.exec {
workingDir(rootDir)
commandLine("node", "--print", "require.resolve('@callstack/react-native-brownfield/package.json')")
}.standardOutput.asText.get().trim()
).parentFile.resolve("gradle-plugin/brownfield")
)
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
```

For standard React Native app layouts, this shorter form also works:

```kotlin
pluginManagement {
includeBuild("../node_modules/@callstack/react-native-brownfield/gradle-plugin/brownfield")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
```

Then remove the Maven classpath dependency from `android/build.gradle`:

```diff
- classpath("com.callstack.react:brownfield-gradle-plugin:<version>")
```

Keep applying the plugin in your brownfield Android library module as usual:

```kotlin
plugins {
id("com.callstack.react.brownfield")
}
```

## 3. Add React Native Dependencies

Add the code below to `reactnativeapp/build.gradle.kts` based on your React Native version.
Expand Down
36 changes: 36 additions & 0 deletions gradle-plugins/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,42 @@ react {
val appProject = project(":app")
```

### From `node_modules` Source

The Maven dependency is the recommended default because it uses the prebuilt plugin and is faster.
Use this source-based setup only when you need to patch the Brownfield Gradle Plugin locally. See the [Android integration docs](../../docs/docs/docs/getting-started/android.mdx#advanced-load-the-plugin-from-node-modules) for details.

Add this to the top of `android/settings.gradle.kts`:

```kotlin
pluginManagement {
includeBuild(
File(
providers.exec {
workingDir(rootDir)
commandLine("node", "--print", "require.resolve('@callstack/react-native-brownfield/package.json')")
}.standardOutput.asText.get().trim()
).parentFile.resolve("gradle-plugin/brownfield")
)
}
```

For standard React Native app layouts, this shorter form also works:

```kotlin
pluginManagement {
includeBuild("../node_modules/@callstack/react-native-brownfield/gradle-plugin/brownfield")
}
```

Then remove the Maven classpath dependency:

```diff
- classpath("com.callstack.react:brownfield-gradle-plugin:1.1.0")
```

Keep using `id("com.callstack.react.brownfield")` in your brownfield Android library module.

## API Usage

- **About Dependencies**
Expand Down
2 changes: 1 addition & 1 deletion gradle-plugins/react/brownfield/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
kotlinJvm = "2.0.21"
kotlinJvm = "2.2.21"
Comment thread
MrMuzyk marked this conversation as resolved.
ktlint = "12.1.1"
detekt = "1.23.7"
agp = "8.5.2"
Expand Down
7 changes: 7 additions & 0 deletions gradle-plugins/react/brownfield/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
Comment on lines +1 to +7

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why these changes are required?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without these, composite build can't resolve the plugin's dependencies.

Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class ProjectConfigurations(private val project: Project) {
Logging.log("created configuration $configName ✅")
}

private fun <T> copyAttribute(
private fun <T : Any> copyAttribute(
key: Attribute<T>,
from: AttributeContainer,
into: AttributeContainer,
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-brownfield/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/gradle-plugin/
6 changes: 4 additions & 2 deletions packages/react-native-brownfield/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@
"build": "bob build",
"dev": "nodemon --exitcrash false --ext '*' --watch src --exec \"bob build\"",
"build:brownfield": "yarn run build",
"prepack": "cp ../../README.md ./README.md",
"postpack": "rm ./README.md",
"sync:gradle-plugin": "node ./scripts/sync-gradle-plugin-source.js",
"prepack": "node ./scripts/sync-gradle-plugin-source.js && cp ../../README.md ./README.md",
"postpack": "node ./scripts/sync-gradle-plugin-source.js --clean && rm ./README.md",
"test": "vitest run"
},
"keywords": [
Expand All @@ -63,6 +64,7 @@
"src",
"lib",
"scripts",
"gradle-plugin",
"android",
"ios",
"cpp",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Copies the Brownfield Gradle plugin source from gradle-plugins/react/brownfield/
* into packages/react-native-brownfield/gradle-plugin/brownfield/ so that the
* plugin source is included in the published npm package.
*
* This enables consumers to use the plugin as a composite build via includeBuild
* from node_modules instead of downloading it from Maven Central — useful for
* local patching or working with an unreleased version.
*
* Run with --clean to remove the copied output (e.g. after publishing or testing).
*
* Usage:
* node sync-gradle-plugin-source.js # copy
* node sync-gradle-plugin-source.js --clean # remove
*/
const fs = require('node:fs');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this file is copying the source of brownfield plugin to packages/react-native-brownfield? If correct, can you add some comments regarding the scope of this file for easier readability?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

const path = require('node:path');

const packageRoot = path.resolve(__dirname, '..');
const repoRoot = path.resolve(packageRoot, '..', '..');

const sourceBrownfieldPath = path.join(
repoRoot,
'gradle-plugins',
'react',
'brownfield'
);

const targetRoot = path.join(packageRoot, 'gradle-plugin');
const targetBrownfieldPath = path.join(targetRoot, 'brownfield');

if (process.argv.includes('--clean')) {
// Remove the copied gradle-plugin directory from the package
fs.rmSync(targetRoot, { recursive: true, force: true });
process.exit(0);
}

// Always start from a clean slate to avoid stale files
fs.rmSync(targetRoot, { recursive: true, force: true });

fs.cpSync(sourceBrownfieldPath, targetBrownfieldPath, {
recursive: true,
// Exclude Gradle build artefacts and local state that should not be shipped
filter(source) {
const relativePath = path.relative(sourceBrownfieldPath, source);
const parts = relativePath.split(path.sep);

return !parts.some((part) =>
['build', '.gradle', 'local.properties', '.kotlin', 'bin'].includes(part)
);
},
});