Skip to content

Commit c4410f6

Browse files
authored
fix: brownfield Gradle Plugin not to depend on *UpdatesResources task from expo-updates if absent (#401)
* fix: brownfield Gradle Plugin not to depend on *UpdatesResources task from expo-updates if absent * chore: bump up BGP version * refactor: use lazy Gradle syntax * fix(test): skip MacOS-specific tests on Ubuntu runners * ci: run MacOS-specific vitest tests in native iOS workflow * feat: unify approach to expo-updates, downstream from #360
1 parent d615310 commit c4410f6

11 files changed

Lines changed: 126 additions & 90 deletions

File tree

.changeset/fair-swans-remain.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@callstack/react-native-brownfield': patch
3+
---
4+
5+
fix: brownfield Gradle Plugin not to depend on \*UpdatesResources task from expo-updates if it is absent

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ jobs:
123123
CLANG_MODULE_CACHE_PATH="$RUNNER_TEMP/swift-cache/clang" \
124124
swift test --scratch-path "$RUNNER_TEMP/swift-cache/swiftpm"
125125
126+
- name: Run brownfield tests including MacOS-only tests
127+
run: |
128+
cd packages/react-native-brownfield
129+
yarn test
130+
126131
android-androidapp-expo:
127132
name: Android road test (AndroidApp - Expo ${{ matrix.version }})
128133
runs-on: ubuntu-latest

apps/RNApp/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ buildscript {
1616
classpath("com.android.tools.build:gradle")
1717
classpath("com.facebook.react:react-native-gradle-plugin")
1818
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
19-
classpath("com.callstack.react:brownfield-gradle-plugin:2.0.0-alpha02-SNAPSHOT")
19+
classpath("com.callstack.react:brownfield-gradle-plugin:2.0.0-alpha03-SNAPSHOT")
2020
}
2121
}
2222

apps/scripts/prepare-android-build-gradle-for-ci.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ if (!projectDirName) {
99

1010
const __filename = fileURLToPath(import.meta.url);
1111
const __dirname = path.dirname(__filename);
12-
const SNAPSHOT_VERSION = '2.0.0-alpha02-SNAPSHOT';
12+
const SNAPSHOT_VERSION = '2.0.0-alpha03-SNAPSHOT';
1313
const targetPath = path.resolve(
1414
__dirname,
1515
'..',

gradle-plugins/react/brownfield/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PROJECT_ID=com.callstack.react.brownfield
22
ARTIFACT_ID=brownfield-gradle-plugin
3-
VERSION=2.0.0-alpha02
3+
VERSION=2.0.0-alpha03
44
GROUP=com.callstack.react
55
IMPLEMENTATION_CLASS=com.callstack.react.brownfield.plugin.RNBrownfieldPlugin
66

gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/plugin/RNSourceSets.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,33 @@ object RNSourceSets {
5555
isDebuggable = variant.debuggable,
5656
)
5757
val capitalizedBundledAssetsVariantName = bundledAssetsVariantName.capitalized()
58+
val appProject = getAppProject()
5859

5960
// 3. Lazily configure the 'variant-specific' source set using .named()
6061
androidExtension.sourceSets.named(variantName) { sourceSet ->
61-
// Paths are collected and added, similar to your improved version
6262
val bundlePathSegments =
6363
listOf(
6464
// outputs for RN <= 0.81
6565
"createBundle${capitalizedBundledAssetsVariantName}JsAndAssets",
6666
// outputs for RN >= 0.82
6767
"react/$bundledAssetsVariantName",
68-
// expo update resources
69-
"create${capitalizedBundledAssetsVariantName}UpdatesResources",
7068
)
69+
val updateResourcesPathSegment = Utils.getExpoUpdatesResourcesTaskName(variant.name)
7170

7271
// Add the variant-specific generated asset and resource directories
7372
val appBuildDir = getAppBuildDir()
7473
sourceSet.assets.srcDirs(bundlePathSegments.map { "$appBuildDir/generated/assets/$it" })
7574
sourceSet.res.srcDirs(bundlePathSegments.map { "$appBuildDir/generated/res/$it" })
7675
sourceSet.jniLibs.srcDirs("libs${variantName.capitalized()}")
76+
if (Utils.hasExpoUpdates(appProject, variant.name)) {
77+
val updateResourcesTask = appProject.tasks.named(updateResourcesPathSegment)
78+
sourceSet.assets.srcDir(
79+
project.files("$appBuildDir/generated/assets/$updateResourcesPathSegment").builtBy(updateResourcesTask),
80+
)
81+
sourceSet.res.srcDir(
82+
project.files("$appBuildDir/generated/res/$updateResourcesPathSegment").builtBy(updateResourcesTask),
83+
)
84+
}
7785
}
7886
}
7987
}

gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/processors/VariantTaskProvider.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,10 @@ class VariantTaskProvider(val project: Project) {
9595
preBuildTask.dependsOn("${appProject.path}:createBundle${capitalizedBundledAssetsVariantName}JsAndAssets")
9696

9797
if (Utils.isExpoProject(project)) {
98-
preBuildTask.dependsOn(
99-
"${appProject.path}:create${capitalizedBundledAssetsVariantName}UpdatesResources",
100-
)
98+
val updatesResourcesTaskName = Utils.getExpoUpdatesResourcesTaskName(variantName)
99+
if (Utils.hasExpoUpdates(appProject, variantName)) {
100+
preBuildTask.dependsOn("${appProject.path}:$updatesResourcesTaskName")
101+
}
101102
}
102103
}
103104
}

gradle-plugins/react/brownfield/src/main/kotlin/com/callstack/react/brownfield/utils/Utils.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ object Utils {
2828
return project.findProject(EXPO_PROJECT_LOCATOR) != null
2929
}
3030

31+
fun getExpoUpdatesResourcesTaskName(variantName: String): String {
32+
return "create${variantName.capitalized()}UpdatesResources"
33+
}
34+
35+
fun hasExpoUpdates(
36+
project: Project,
37+
variantName: String,
38+
): Boolean {
39+
return isExpoProject(project) &&
40+
project.tasks.names.contains(
41+
getExpoUpdatesResourcesTaskName(variantName),
42+
)
43+
}
44+
3145
fun getBundledAssetsVariantName(
3246
variantName: String?,
3347
buildTypeName: String?,

packages/cli/src/brownfield/utils/__tests__/strip-framework-binary.test.ts

Lines changed: 79 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -65,76 +65,91 @@ describe('stripFrameworkBinary', () => {
6565
);
6666
});
6767

68-
it('strips binary from ios-arm64 slice', () => {
69-
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
70-
'ios-arm64',
71-
]);
72-
const binaryPath = path.join(
73-
xcframeworkPath,
74-
'ios-arm64',
75-
'TestFramework.framework',
76-
'TestFramework'
77-
);
78-
const originalContent = fs.readFileSync(binaryPath, 'utf-8');
79-
80-
stripFrameworkBinary(xcframeworkPath);
81-
82-
const newContent = fs.readFileSync(binaryPath);
83-
expect(newContent.toString()).not.toBe(originalContent);
84-
expect(fs.existsSync(binaryPath)).toBe(true);
85-
expect(mockLoggerSuccess).toHaveBeenCalledWith(
86-
'TestFramework.xcframework is now interface-only'
87-
);
88-
});
89-
90-
it('strips binary from simulator slice with fat binary', () => {
91-
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
92-
'ios-arm64_x86_64-simulator',
93-
]);
94-
const binaryPath = path.join(
95-
xcframeworkPath,
96-
'ios-arm64_x86_64-simulator',
97-
'TestFramework.framework',
98-
'TestFramework'
99-
);
100-
const originalContent = fs.readFileSync(binaryPath, 'utf-8');
101-
102-
stripFrameworkBinary(xcframeworkPath);
103-
104-
const newContent = fs.readFileSync(binaryPath);
105-
expect(newContent.toString()).not.toBe(originalContent);
68+
describe.skipIf(process.platform !== 'darwin')('with Xcode toolchain', () => {
69+
it('strips binary from ios-arm64 slice', () => {
70+
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
71+
'ios-arm64',
72+
]);
73+
const binaryPath = path.join(
74+
xcframeworkPath,
75+
'ios-arm64',
76+
'TestFramework.framework',
77+
'TestFramework'
78+
);
79+
const originalContent = fs.readFileSync(binaryPath, 'utf-8');
80+
81+
stripFrameworkBinary(xcframeworkPath);
82+
83+
const newContent = fs.readFileSync(binaryPath);
84+
expect(newContent.toString()).not.toBe(originalContent);
85+
expect(fs.existsSync(binaryPath)).toBe(true);
86+
expect(mockLoggerSuccess).toHaveBeenCalledWith(
87+
'TestFramework.xcframework is now interface-only'
88+
);
89+
});
10690

107-
const archInfo = execSync(`xcrun lipo -info "${binaryPath}"`, {
108-
encoding: 'utf-8',
91+
it('strips binary from simulator slice with fat binary', () => {
92+
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
93+
'ios-arm64_x86_64-simulator',
94+
]);
95+
const binaryPath = path.join(
96+
xcframeworkPath,
97+
'ios-arm64_x86_64-simulator',
98+
'TestFramework.framework',
99+
'TestFramework'
100+
);
101+
const originalContent = fs.readFileSync(binaryPath, 'utf-8');
102+
103+
stripFrameworkBinary(xcframeworkPath);
104+
105+
const newContent = fs.readFileSync(binaryPath);
106+
expect(newContent.toString()).not.toBe(originalContent);
107+
108+
const archInfo = execSync(`xcrun lipo -info "${binaryPath}"`, {
109+
encoding: 'utf-8',
110+
});
111+
expect(archInfo).toContain('arm64');
112+
expect(archInfo).toContain('x86_64');
109113
});
110-
expect(archInfo).toContain('arm64');
111-
expect(archInfo).toContain('x86_64');
112-
});
113114

114-
it('handles multiple slices', () => {
115-
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
116-
'ios-arm64',
117-
'ios-arm64_x86_64-simulator',
118-
]);
115+
it('handles multiple slices', () => {
116+
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
117+
'ios-arm64',
118+
'ios-arm64_x86_64-simulator',
119+
]);
120+
121+
stripFrameworkBinary(xcframeworkPath);
122+
123+
const deviceBinary = path.join(
124+
xcframeworkPath,
125+
'ios-arm64',
126+
'TestFramework.framework',
127+
'TestFramework'
128+
);
129+
const simBinary = path.join(
130+
xcframeworkPath,
131+
'ios-arm64_x86_64-simulator',
132+
'TestFramework.framework',
133+
'TestFramework'
134+
);
135+
136+
expect(fs.existsSync(deviceBinary)).toBe(true);
137+
expect(fs.existsSync(simBinary)).toBe(true);
138+
expect(mockLoggerSuccess).toHaveBeenCalledOnce();
139+
});
119140

120-
stripFrameworkBinary(xcframeworkPath);
141+
it('ignores non-ios directories', () => {
142+
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
143+
'ios-arm64',
144+
]);
145+
fs.mkdirSync(path.join(xcframeworkPath, 'macos-arm64'), {
146+
recursive: true,
147+
});
121148

122-
const deviceBinary = path.join(
123-
xcframeworkPath,
124-
'ios-arm64',
125-
'TestFramework.framework',
126-
'TestFramework'
127-
);
128-
const simBinary = path.join(
129-
xcframeworkPath,
130-
'ios-arm64_x86_64-simulator',
131-
'TestFramework.framework',
132-
'TestFramework'
133-
);
149+
stripFrameworkBinary(xcframeworkPath);
134150

135-
expect(fs.existsSync(deviceBinary)).toBe(true);
136-
expect(fs.existsSync(simBinary)).toBe(true);
137-
expect(mockLoggerSuccess).toHaveBeenCalledOnce();
151+
expect(mockLoggerSuccess).toHaveBeenCalledOnce();
152+
});
138153
});
139154

140155
it('warns and skips unknown slice types', () => {
@@ -164,17 +179,4 @@ describe('stripFrameworkBinary', () => {
164179
expect.stringContaining('No binary found at')
165180
);
166181
});
167-
168-
it('ignores non-ios directories', () => {
169-
const xcframeworkPath = createMockXcframework(tempDir, 'TestFramework', [
170-
'ios-arm64',
171-
]);
172-
fs.mkdirSync(path.join(xcframeworkPath, 'macos-arm64'), {
173-
recursive: true,
174-
});
175-
176-
stripFrameworkBinary(xcframeworkPath);
177-
178-
expect(mockLoggerSuccess).toHaveBeenCalledOnce();
179-
});
180182
});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export const BROWNFIELD_PLUGIN_VERSION = '2.0.0-alpha02';
1+
export const BROWNFIELD_PLUGIN_VERSION = '2.0.0-alpha03';
22
export const brownfieldGradlePluginDependency = `classpath("com.callstack.react:brownfield-gradle-plugin:${BROWNFIELD_PLUGIN_VERSION}")`;

0 commit comments

Comments
 (0)