@react-native/gradle-plugin 0.75.2 → 0.75.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/react-native-gradle-plugin/build.gradle.kts +2 -10
- package/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt +1 -0
- package/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt +11 -2
- package/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/ReactExtensionTest.kt +38 -0
- package/settings-plugin/build.gradle.kts +2 -10
- package/settings-plugin/src/main/kotlin/com/facebook/react/ReactSettingsExtension.kt +83 -23
- package/settings-plugin/src/test/kotlin/com/facebook/react/ReactSettingsExtensionTest.kt +237 -0
- package/shared/build.gradle.kts +2 -1
- package/shared/src/main/kotlin/com/facebook/react/utils/JsonUtils.kt +17 -2
- package/shared/src/test/kotlin/com/facebook/react/utils/JsonUtilsTest.kt +48 -0
- package/shared-testutil/build.gradle.kts +2 -1
package/package.json
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import org.gradle.api.internal.classpath.ModuleRegistry
|
|
9
9
|
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
|
10
|
-
import org.gradle.configurationcache.extensions.serviceOf
|
|
11
10
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
12
11
|
|
|
13
12
|
plugins {
|
|
@@ -52,14 +51,6 @@ dependencies {
|
|
|
52
51
|
testImplementation(libs.junit)
|
|
53
52
|
testImplementation(libs.assertj)
|
|
54
53
|
testImplementation(project(":shared-testutil"))
|
|
55
|
-
|
|
56
|
-
testRuntimeOnly(
|
|
57
|
-
files(
|
|
58
|
-
serviceOf<ModuleRegistry>()
|
|
59
|
-
.getModule("gradle-tooling-api-builders")
|
|
60
|
-
.classpath
|
|
61
|
-
.asFiles
|
|
62
|
-
.first()))
|
|
63
54
|
}
|
|
64
55
|
|
|
65
56
|
// We intentionally don't build for Java 17 as users will see a cryptic bytecode version
|
|
@@ -74,7 +65,8 @@ tasks.withType<KotlinCompile>().configureEach {
|
|
|
74
65
|
apiVersion = "1.6"
|
|
75
66
|
// See comment above on JDK 11 support
|
|
76
67
|
jvmTarget = "11"
|
|
77
|
-
allWarningsAsErrors =
|
|
68
|
+
allWarningsAsErrors =
|
|
69
|
+
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
|
|
78
70
|
}
|
|
79
71
|
}
|
|
80
72
|
|
|
@@ -188,6 +188,7 @@ abstract class ReactExtension @Inject constructor(val project: Project) {
|
|
|
188
188
|
?.dependencies
|
|
189
189
|
?.values
|
|
190
190
|
?.filter { it.platforms?.android !== null }
|
|
191
|
+
?.filterNot { it.platforms?.android?.isPureCxxDependency == true }
|
|
191
192
|
?.forEach { deps ->
|
|
192
193
|
val nameCleansed = deps.nameCleansed
|
|
193
194
|
val dependencyConfiguration = deps.platforms?.android?.dependencyConfiguration
|
|
@@ -30,10 +30,19 @@ abstract class GeneratePackageListTask : DefaultTask() {
|
|
|
30
30
|
|
|
31
31
|
@TaskAction
|
|
32
32
|
fun taskAction() {
|
|
33
|
-
val model =
|
|
33
|
+
val model =
|
|
34
|
+
JsonUtils.fromAutolinkingConfigJson(autolinkInputFile.get().asFile)
|
|
35
|
+
?: error(
|
|
36
|
+
"""
|
|
37
|
+
RNGP - Autolinking: Could not parse autolinking config file:
|
|
38
|
+
${autolinkInputFile.get().asFile.absolutePath}
|
|
39
|
+
|
|
40
|
+
The file is either missing or not containing valid JSON so the build won't succeed.
|
|
41
|
+
"""
|
|
42
|
+
.trimIndent())
|
|
34
43
|
|
|
35
44
|
val packageName =
|
|
36
|
-
model
|
|
45
|
+
model.project?.android?.packageName
|
|
37
46
|
?: error(
|
|
38
47
|
"RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field.")
|
|
39
48
|
|
|
@@ -189,6 +189,44 @@ class ReactExtensionTest {
|
|
|
189
189
|
assertThat(deps).isEmpty()
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
@Test
|
|
193
|
+
fun getGradleDependenciesToApply_withIsPureCxxDeps_filtersCorrectly() {
|
|
194
|
+
val validJsonFile =
|
|
195
|
+
createJsonFile(
|
|
196
|
+
"""
|
|
197
|
+
{
|
|
198
|
+
"reactNativeVersion": "1000.0.0",
|
|
199
|
+
"dependencies": {
|
|
200
|
+
"@react-native/oss-library-example": {
|
|
201
|
+
"root": "./node_modules/@react-native/android-example",
|
|
202
|
+
"name": "@react-native/android-example",
|
|
203
|
+
"platforms": {
|
|
204
|
+
"android": {
|
|
205
|
+
"sourceDir": "src/main/java",
|
|
206
|
+
"packageImportPath": "com.facebook.react"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"@react-native/another-library-for-testing": {
|
|
211
|
+
"root": "./node_modules/@react-native/cxx-testing",
|
|
212
|
+
"name": "@react-native/cxx-testing",
|
|
213
|
+
"platforms": {
|
|
214
|
+
"android": {
|
|
215
|
+
"sourceDir": "src/main/java",
|
|
216
|
+
"packageImportPath": "com.facebook.react",
|
|
217
|
+
"isPureCxxDependency": true
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
"""
|
|
224
|
+
.trimIndent())
|
|
225
|
+
|
|
226
|
+
val deps = getGradleDependenciesToApply(validJsonFile)
|
|
227
|
+
assertThat(deps).containsExactly("implementation" to ":react-native_android-example")
|
|
228
|
+
}
|
|
229
|
+
|
|
192
230
|
private fun createJsonFile(@Language("JSON") input: String) =
|
|
193
231
|
tempFolder.newFile().apply { writeText(input) }
|
|
194
232
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import org.gradle.api.internal.classpath.ModuleRegistry
|
|
9
9
|
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
|
10
|
-
import org.gradle.configurationcache.extensions.serviceOf
|
|
11
10
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
12
11
|
|
|
13
12
|
plugins {
|
|
@@ -41,14 +40,6 @@ dependencies {
|
|
|
41
40
|
|
|
42
41
|
testImplementation(libs.junit)
|
|
43
42
|
testImplementation(project(":shared-testutil"))
|
|
44
|
-
|
|
45
|
-
testRuntimeOnly(
|
|
46
|
-
files(
|
|
47
|
-
serviceOf<ModuleRegistry>()
|
|
48
|
-
.getModule("gradle-tooling-api-builders")
|
|
49
|
-
.classpath
|
|
50
|
-
.asFiles
|
|
51
|
-
.first()))
|
|
52
43
|
}
|
|
53
44
|
|
|
54
45
|
// We intentionally don't build for Java 17 as users will see a cryptic bytecode version
|
|
@@ -63,7 +54,8 @@ tasks.withType<KotlinCompile>().configureEach {
|
|
|
63
54
|
apiVersion = "1.6"
|
|
64
55
|
// See comment above on JDK 11 support
|
|
65
56
|
jvmTarget = "11"
|
|
66
|
-
allWarningsAsErrors =
|
|
57
|
+
allWarningsAsErrors =
|
|
58
|
+
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
|
|
67
59
|
}
|
|
68
60
|
}
|
|
69
61
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react
|
|
9
9
|
|
|
10
|
+
import com.facebook.react.model.ModelAutolinkingConfigJson
|
|
10
11
|
import com.facebook.react.utils.JsonUtils
|
|
11
12
|
import com.facebook.react.utils.windowsAwareCommandLine
|
|
12
13
|
import java.io.File
|
|
@@ -53,30 +54,22 @@ abstract class ReactSettingsExtension @Inject constructor(val settings: Settings
|
|
|
53
54
|
.files("yarn.lock", "package-lock.json", "package.json", "react-native.config.js")
|
|
54
55
|
) {
|
|
55
56
|
outputFile.parentFile.mkdirs()
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
val message =
|
|
69
|
-
if (!finished) "${prefixCommand} timed out"
|
|
70
|
-
else "${prefixCommand} exited with error code: ${process.exitValue()}"
|
|
71
|
-
val logger = Logging.getLogger("ReactSettingsExtension")
|
|
72
|
-
logger.error(message)
|
|
73
|
-
if (outputFile.length() != 0L) {
|
|
74
|
-
logger.error(outputFile.readText().substring(0, 1024))
|
|
57
|
+
|
|
58
|
+
val updateConfig =
|
|
59
|
+
object : GenerateConfig {
|
|
60
|
+
private val pb =
|
|
61
|
+
ProcessBuilder(command)
|
|
62
|
+
.directory(workingDirectory)
|
|
63
|
+
.redirectOutput(ProcessBuilder.Redirect.to(outputFile))
|
|
64
|
+
.redirectError(ProcessBuilder.Redirect.INHERIT)
|
|
65
|
+
|
|
66
|
+
override fun command(): List<String> = pb.command()
|
|
67
|
+
|
|
68
|
+
override fun start(): Process = pb.start()
|
|
75
69
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
70
|
+
|
|
71
|
+
checkAndUpdateCache(updateConfig, outputFile, outputFolder, lockFiles)
|
|
72
|
+
|
|
80
73
|
linkLibraries(getLibrariesToAutolink(outputFile))
|
|
81
74
|
}
|
|
82
75
|
|
|
@@ -107,9 +100,73 @@ abstract class ReactSettingsExtension @Inject constructor(val settings: Settings
|
|
|
107
100
|
}
|
|
108
101
|
}
|
|
109
102
|
|
|
103
|
+
internal interface GenerateConfig {
|
|
104
|
+
fun command(): List<String>
|
|
105
|
+
|
|
106
|
+
fun start(): Process
|
|
107
|
+
}
|
|
108
|
+
|
|
110
109
|
companion object {
|
|
111
110
|
private val md = MessageDigest.getInstance("SHA-256")
|
|
112
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Determine if our cache is out-of-date
|
|
114
|
+
*
|
|
115
|
+
* @param cacheJsonConfig Our current cached autolinking.json config, which may exist
|
|
116
|
+
* @param cacheFolder The folder we store our cached SHAs and config
|
|
117
|
+
* @param lockFiles The [FileCollection] of the lockfiles to check.
|
|
118
|
+
* @return `true` if the cache needs to be rebuilt, `false` otherwise
|
|
119
|
+
*/
|
|
120
|
+
internal fun isCacheDirty(
|
|
121
|
+
cacheJsonConfig: File,
|
|
122
|
+
cacheFolder: File,
|
|
123
|
+
lockFiles: FileCollection,
|
|
124
|
+
): Boolean {
|
|
125
|
+
if (cacheJsonConfig.exists().not() || cacheJsonConfig.length() == 0L) {
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
val lockFilesChanged = checkAndUpdateLockfiles(lockFiles, cacheFolder)
|
|
129
|
+
if (lockFilesChanged) {
|
|
130
|
+
return true
|
|
131
|
+
}
|
|
132
|
+
return isConfigModelInvalid(JsonUtils.fromAutolinkingConfigJson(cacheJsonConfig))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Utility function to update the settings cache only if it's entries are dirty
|
|
137
|
+
*
|
|
138
|
+
* @param updateJsonConfig A [GenerateConfig] to update the project's autolinking config
|
|
139
|
+
* @param cacheJsonConfig Our current cached autolinking.json config, which may exist
|
|
140
|
+
* @param cacheFolder The folder we store our cached SHAs and config
|
|
141
|
+
* @param lockFiles The [FileCollection] of the lockfiles to check.
|
|
142
|
+
*/
|
|
143
|
+
internal fun checkAndUpdateCache(
|
|
144
|
+
updateJsonConfig: GenerateConfig,
|
|
145
|
+
cacheJsonConfig: File,
|
|
146
|
+
cacheFolder: File,
|
|
147
|
+
lockFiles: FileCollection,
|
|
148
|
+
) {
|
|
149
|
+
if (isCacheDirty(cacheJsonConfig, cacheFolder, lockFiles)) {
|
|
150
|
+
val process = updateJsonConfig.start()
|
|
151
|
+
|
|
152
|
+
val finished = process.waitFor(5, TimeUnit.MINUTES)
|
|
153
|
+
if (!finished || (process.exitValue() != 0)) {
|
|
154
|
+
val command = updateJsonConfig.command().joinToString(" ")
|
|
155
|
+
val prefixCommand = "ERROR: autolinkLibrariesFromCommand: process $command"
|
|
156
|
+
val message =
|
|
157
|
+
if (!finished) "$prefixCommand timed out"
|
|
158
|
+
else "$prefixCommand exited with error code: ${process.exitValue()}"
|
|
159
|
+
val logger = Logging.getLogger("ReactSettingsExtension")
|
|
160
|
+
logger.error(message)
|
|
161
|
+
if (cacheJsonConfig.length() != 0L) {
|
|
162
|
+
logger.error(cacheJsonConfig.readText().substring(0, 1024))
|
|
163
|
+
}
|
|
164
|
+
cacheJsonConfig.delete()
|
|
165
|
+
throw GradleException(message)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
113
170
|
/**
|
|
114
171
|
* Utility function to check if the provided lockfiles have been updated or not. This function
|
|
115
172
|
* will both check and update the lockfiles hashes if necessary.
|
|
@@ -150,5 +207,8 @@ abstract class ReactSettingsExtension @Inject constructor(val settings: Settings
|
|
|
150
207
|
|
|
151
208
|
internal fun computeSha256(lockFile: File) =
|
|
152
209
|
String.format("%032x", BigInteger(1, md.digest(lockFile.readBytes())))
|
|
210
|
+
|
|
211
|
+
internal fun isConfigModelInvalid(model: ModelAutolinkingConfigJson?) =
|
|
212
|
+
model?.project?.android?.packageName == null
|
|
153
213
|
}
|
|
154
214
|
}
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
package com.facebook.react
|
|
9
9
|
|
|
10
|
+
import com.facebook.react.ReactSettingsExtension.Companion.checkAndUpdateCache
|
|
10
11
|
import com.facebook.react.ReactSettingsExtension.Companion.checkAndUpdateLockfiles
|
|
11
12
|
import com.facebook.react.ReactSettingsExtension.Companion.computeSha256
|
|
12
13
|
import com.facebook.react.ReactSettingsExtension.Companion.getLibrariesToAutolink
|
|
13
14
|
import groovy.test.GroovyTestCase.assertEquals
|
|
15
|
+
import com.facebook.react.ReactSettingsExtension.GenerateConfig
|
|
14
16
|
import java.io.File
|
|
15
17
|
import org.gradle.testfixtures.ProjectBuilder
|
|
16
18
|
import org.intellij.lang.annotations.Language
|
|
@@ -236,6 +238,241 @@ class ReactSettingsExtensionTest {
|
|
|
236
238
|
File(buildFolder, "package-lock.json.sha").readText())
|
|
237
239
|
}
|
|
238
240
|
|
|
241
|
+
@Test
|
|
242
|
+
fun skipUpdateIfConfigInCacheIsValid() {
|
|
243
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
244
|
+
val buildFolder = tempFolder.newFolder("build")
|
|
245
|
+
val generatedFolder = tempFolder.newFolder("build", "generated")
|
|
246
|
+
val outputFile =
|
|
247
|
+
File(generatedFolder, "autolinking.json").apply {
|
|
248
|
+
writeText(
|
|
249
|
+
"""
|
|
250
|
+
{
|
|
251
|
+
"root": "/",
|
|
252
|
+
"reactNativePath": "/node_modules/react-native",
|
|
253
|
+
"reactNativeVersion": "0.75",
|
|
254
|
+
"dependencies": {},
|
|
255
|
+
"healthChecks": [],
|
|
256
|
+
"platforms": {
|
|
257
|
+
"ios": {},
|
|
258
|
+
"android": {}
|
|
259
|
+
},
|
|
260
|
+
"assets": [],
|
|
261
|
+
"project": {
|
|
262
|
+
"ios": {},
|
|
263
|
+
"android": {
|
|
264
|
+
"sourceDir": "/",
|
|
265
|
+
"appName": "app",
|
|
266
|
+
"packageName": "com.TestApp",
|
|
267
|
+
"applicationId": "com.TestApp",
|
|
268
|
+
"mainActivity": ".MainActivity",
|
|
269
|
+
"assets": []
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
"""
|
|
274
|
+
.trimIndent())
|
|
275
|
+
}
|
|
276
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
277
|
+
val lockfileCollection = project.files("yarn.lock")
|
|
278
|
+
|
|
279
|
+
// Prebuild the shas with the invalid empty autolinking.json
|
|
280
|
+
checkAndUpdateLockfiles(lockfileCollection, buildFolder)
|
|
281
|
+
|
|
282
|
+
val monitoredUpdateConfig = createMonitoredUpdateConfig()
|
|
283
|
+
|
|
284
|
+
checkAndUpdateCache(monitoredUpdateConfig, outputFile, buildFolder, lockfileCollection)
|
|
285
|
+
|
|
286
|
+
// The autolinking.json file is valid, SHA's are untouched therefore config should NOT be
|
|
287
|
+
// refreshed
|
|
288
|
+
assertThat(monitoredUpdateConfig.run).isFalse()
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@Test
|
|
292
|
+
fun checkAndUpdateConfigIfEmpty() {
|
|
293
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
294
|
+
val buildFolder = tempFolder.newFolder("build")
|
|
295
|
+
val generatedFolder = tempFolder.newFolder("build", "generated")
|
|
296
|
+
val outputFile = File(generatedFolder, "autolinking.json").apply { writeText("") }
|
|
297
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
298
|
+
val lockfileCollection = project.files("yarn.lock")
|
|
299
|
+
|
|
300
|
+
// Prebuild the shas with the invalid empty autolinking.json
|
|
301
|
+
checkAndUpdateLockfiles(lockfileCollection, buildFolder)
|
|
302
|
+
|
|
303
|
+
val monitoredUpdateConfig = createMonitoredUpdateConfig()
|
|
304
|
+
|
|
305
|
+
checkAndUpdateCache(monitoredUpdateConfig, outputFile, buildFolder, lockfileCollection)
|
|
306
|
+
|
|
307
|
+
// The autolinking.json file is invalid and should be refreshed
|
|
308
|
+
assertThat(monitoredUpdateConfig.run).isTrue()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@Test
|
|
312
|
+
fun checkAndUpdateConfigIfCachedConfigInvalid() {
|
|
313
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
314
|
+
val buildFolder = tempFolder.newFolder("build")
|
|
315
|
+
val generatedFolder = tempFolder.newFolder("build", "generated")
|
|
316
|
+
val outputFile =
|
|
317
|
+
File(generatedFolder, "autolinking.json").apply {
|
|
318
|
+
writeText(
|
|
319
|
+
"""
|
|
320
|
+
{
|
|
321
|
+
"project": {
|
|
322
|
+
"ios": {},
|
|
323
|
+
"android": {}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
"""
|
|
327
|
+
.trimIndent())
|
|
328
|
+
}
|
|
329
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
330
|
+
val lockfileCollection = project.files("yarn.lock")
|
|
331
|
+
|
|
332
|
+
// Prebuild the shas with the invalid empty autolinking.json
|
|
333
|
+
checkAndUpdateLockfiles(lockfileCollection, buildFolder)
|
|
334
|
+
|
|
335
|
+
val monitoredUpdateConfig = createMonitoredUpdateConfig()
|
|
336
|
+
|
|
337
|
+
checkAndUpdateCache(monitoredUpdateConfig, outputFile, buildFolder, lockfileCollection)
|
|
338
|
+
|
|
339
|
+
// The autolinking.json file is invalid and should be refreshed
|
|
340
|
+
assertThat(monitoredUpdateConfig.run).isTrue()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@Test
|
|
344
|
+
fun isCacheDirty_withMissingAutolinkingFile_returnsTrue() {
|
|
345
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
346
|
+
val buildFolder =
|
|
347
|
+
tempFolder.newFolder("build").apply {
|
|
348
|
+
File(this, "yarn.lock.sha")
|
|
349
|
+
.writeText("76046b72442ee7eb130627e56c3db7c9907eef4913b17ad130335edc0eb702a8")
|
|
350
|
+
}
|
|
351
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
352
|
+
val lockfiles = project.files("yarn.lock")
|
|
353
|
+
val emptyConfigFile = File(tempFolder.newFolder("build", "autolinking"), "autolinking.json")
|
|
354
|
+
|
|
355
|
+
assertThat(ReactSettingsExtension.isCacheDirty(emptyConfigFile, buildFolder, lockfiles))
|
|
356
|
+
.isTrue()
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
@Test
|
|
360
|
+
fun isCacheDirty_withInvalidAutolinkingFile_returnsTrue() {
|
|
361
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
362
|
+
val buildFolder =
|
|
363
|
+
tempFolder.newFolder("build").apply {
|
|
364
|
+
File(this, "yarn.lock.sha")
|
|
365
|
+
.writeText("76046b72442ee7eb130627e56c3db7c9907eef4913b17ad130335edc0eb702a8")
|
|
366
|
+
}
|
|
367
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
368
|
+
val lockfiles = project.files("yarn.lock")
|
|
369
|
+
val invalidConfigFile =
|
|
370
|
+
createJsonFile(
|
|
371
|
+
"""
|
|
372
|
+
{}
|
|
373
|
+
"""
|
|
374
|
+
.trimIndent())
|
|
375
|
+
|
|
376
|
+
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
|
|
377
|
+
.isTrue()
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@Test
|
|
381
|
+
fun isCacheDirty_withMissingDependenciesInJson_returnsFalse() {
|
|
382
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
383
|
+
val buildFolder =
|
|
384
|
+
tempFolder.newFolder("build").apply {
|
|
385
|
+
File(this, "yarn.lock.sha")
|
|
386
|
+
.writeText("76046b72442ee7eb130627e56c3db7c9907eef4913b17ad130335edc0eb702a8")
|
|
387
|
+
}
|
|
388
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
389
|
+
val lockfiles = project.files("yarn.lock")
|
|
390
|
+
val invalidConfigFile =
|
|
391
|
+
createJsonFile(
|
|
392
|
+
"""
|
|
393
|
+
{
|
|
394
|
+
"reactNativeVersion": "1000.0.0"
|
|
395
|
+
}
|
|
396
|
+
"""
|
|
397
|
+
.trimIndent())
|
|
398
|
+
|
|
399
|
+
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
|
|
400
|
+
.isTrue()
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
@Test
|
|
404
|
+
fun isCacheDirty_withExistingEmptyDependenciesInJson_returnsTrue() {
|
|
405
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
406
|
+
val buildFolder =
|
|
407
|
+
tempFolder.newFolder("build").apply {
|
|
408
|
+
File(this, "yarn.lock.sha")
|
|
409
|
+
.writeText("76046b72442ee7eb130627e56c3db7c9907eef4913b17ad130335edc0eb702a8")
|
|
410
|
+
}
|
|
411
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
412
|
+
val lockfiles = project.files("yarn.lock")
|
|
413
|
+
val invalidConfigFile =
|
|
414
|
+
createJsonFile(
|
|
415
|
+
"""
|
|
416
|
+
{
|
|
417
|
+
"reactNativeVersion": "1000.0.0",
|
|
418
|
+
"dependencies": {}
|
|
419
|
+
}
|
|
420
|
+
"""
|
|
421
|
+
.trimIndent())
|
|
422
|
+
|
|
423
|
+
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
|
|
424
|
+
.isTrue()
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
@Test
|
|
428
|
+
fun isCacheDirty_withExistingDependenciesInJson_returnsTrue() {
|
|
429
|
+
val project = ProjectBuilder.builder().withProjectDir(tempFolder.root).build()
|
|
430
|
+
val buildFolder =
|
|
431
|
+
tempFolder.newFolder("build").apply {
|
|
432
|
+
File(this, "yarn.lock.sha")
|
|
433
|
+
.writeText("76046b72442ee7eb130627e56c3db7c9907eef4913b17ad130335edc0eb702a8")
|
|
434
|
+
}
|
|
435
|
+
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
|
|
436
|
+
val lockfiles = project.files("yarn.lock")
|
|
437
|
+
val invalidConfigFile =
|
|
438
|
+
createJsonFile(
|
|
439
|
+
"""
|
|
440
|
+
{
|
|
441
|
+
"reactNativeVersion": "1000.0.0",
|
|
442
|
+
"dependencies": {
|
|
443
|
+
"@react-native/oss-library-example": {
|
|
444
|
+
"root": "./node_modules/@react-native/oss-library-example",
|
|
445
|
+
"name": "@react-native/oss-library-example",
|
|
446
|
+
"platforms": {
|
|
447
|
+
"ios": {
|
|
448
|
+
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
|
|
449
|
+
"version": "0.0.1",
|
|
450
|
+
"configurations": [],
|
|
451
|
+
"scriptPhases": []
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
"""
|
|
458
|
+
.trimIndent())
|
|
459
|
+
|
|
460
|
+
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
|
|
461
|
+
.isTrue()
|
|
462
|
+
}
|
|
463
|
+
|
|
239
464
|
private fun createJsonFile(@Language("JSON") input: String) =
|
|
240
465
|
tempFolder.newFile().apply { writeText(input) }
|
|
466
|
+
|
|
467
|
+
private fun createMonitoredUpdateConfig() =
|
|
468
|
+
object : GenerateConfig {
|
|
469
|
+
var run = false
|
|
470
|
+
|
|
471
|
+
override fun start(): Process {
|
|
472
|
+
run = true
|
|
473
|
+
return ProcessBuilder("true").start()
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
override fun command(): List<String> = listOf("true")
|
|
477
|
+
}
|
|
241
478
|
}
|
package/shared/build.gradle.kts
CHANGED
|
@@ -29,7 +29,8 @@ tasks.withType<KotlinCompile>().configureEach {
|
|
|
29
29
|
kotlinOptions {
|
|
30
30
|
apiVersion = "1.6"
|
|
31
31
|
jvmTarget = "11"
|
|
32
|
-
allWarningsAsErrors =
|
|
32
|
+
allWarningsAsErrors =
|
|
33
|
+
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -21,8 +21,23 @@ object JsonUtils {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
fun fromAutolinkingConfigJson(input: File): ModelAutolinkingConfigJson? =
|
|
24
|
-
input.bufferedReader().use {
|
|
25
|
-
runCatching {
|
|
24
|
+
input.bufferedReader().use { reader ->
|
|
25
|
+
runCatching {
|
|
26
|
+
// We sanitize the output of the `config` command as it could contain debug logs
|
|
27
|
+
// such as:
|
|
28
|
+
//
|
|
29
|
+
// > AwesomeProject@0.0.1 npx
|
|
30
|
+
// > rnc-cli config
|
|
31
|
+
//
|
|
32
|
+
// which will render the JSON invalid.
|
|
33
|
+
val content =
|
|
34
|
+
reader
|
|
35
|
+
.readLines()
|
|
36
|
+
.filterNot { line -> line.startsWith(">") }
|
|
37
|
+
.joinToString("\n")
|
|
38
|
+
.trim()
|
|
39
|
+
gsonConverter.fromJson(content, ModelAutolinkingConfigJson::class.java)
|
|
40
|
+
}
|
|
26
41
|
.getOrNull()
|
|
27
42
|
}
|
|
28
43
|
}
|
|
@@ -185,6 +185,54 @@ class JsonUtilsTest {
|
|
|
185
185
|
assertEquals("implementation", parsed.project!!.android!!.dependencyConfiguration)
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
@Test
|
|
189
|
+
fun fromAutolinkingConfigJson_withInfoLogs_sanitizeAndParseIt() {
|
|
190
|
+
@Suppress("JsonStandardCompliance")
|
|
191
|
+
val validJson =
|
|
192
|
+
createJsonFile(
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
> AwesomeProject@0.0.1 npx
|
|
196
|
+
> rnc-cli config
|
|
197
|
+
|
|
198
|
+
{
|
|
199
|
+
"reactNativeVersion": "1000.0.0",
|
|
200
|
+
"project": {
|
|
201
|
+
"ios": {
|
|
202
|
+
"sourceDir": "./packages/rn-tester",
|
|
203
|
+
"xcodeProject": {
|
|
204
|
+
"name": "RNTesterPods.xcworkspace",
|
|
205
|
+
"isWorkspace": true
|
|
206
|
+
},
|
|
207
|
+
"automaticPodsInstallation": false
|
|
208
|
+
},
|
|
209
|
+
"android": {
|
|
210
|
+
"sourceDir": "./packages/rn-tester",
|
|
211
|
+
"appName": "RN-Tester",
|
|
212
|
+
"packageName": "com.facebook.react.uiapp",
|
|
213
|
+
"applicationId": "com.facebook.react.uiapp",
|
|
214
|
+
"mainActivity": ".RNTesterActivity",
|
|
215
|
+
"watchModeCommandParams": [
|
|
216
|
+
"--mode HermesDebug"
|
|
217
|
+
],
|
|
218
|
+
"dependencyConfiguration": "implementation"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
"""
|
|
223
|
+
.trimIndent())
|
|
224
|
+
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!
|
|
225
|
+
|
|
226
|
+
assertThat("./packages/rn-tester").isEqualTo(parsed.project!!.android!!.sourceDir)
|
|
227
|
+
assertThat("RN-Tester").isEqualTo(parsed.project!!.android!!.appName)
|
|
228
|
+
assertThat("com.facebook.react.uiapp").isEqualTo(parsed.project!!.android!!.packageName)
|
|
229
|
+
assertThat("com.facebook.react.uiapp").isEqualTo(parsed.project!!.android!!.applicationId)
|
|
230
|
+
assertThat(".RNTesterActivity").isEqualTo(parsed.project!!.android!!.mainActivity)
|
|
231
|
+
assertThat("--mode HermesDebug")
|
|
232
|
+
.isEqualTo(parsed.project!!.android!!.watchModeCommandParams!![0])
|
|
233
|
+
assertThat("implementation").isEqualTo(parsed.project!!.android!!.dependencyConfiguration)
|
|
234
|
+
}
|
|
235
|
+
|
|
188
236
|
@Test
|
|
189
237
|
fun fromAutolinkingConfigJson_withDependenciesSpecified_canParseIt() {
|
|
190
238
|
val validJson =
|
|
@@ -24,7 +24,8 @@ tasks.withType<KotlinCompile>().configureEach {
|
|
|
24
24
|
kotlinOptions {
|
|
25
25
|
apiVersion = "1.6"
|
|
26
26
|
jvmTarget = "11"
|
|
27
|
-
allWarningsAsErrors =
|
|
27
|
+
allWarningsAsErrors =
|
|
28
|
+
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|