Skip to content

Commit 1df1570

Browse files
cortinicofacebook-github-bot
authored andcommitted
RNGP - Setup the RunAutolinkingConfigTask to run the config command
Summary: This diff is part of RFC0759 react-native-community/discussions-and-proposals#759 Here I'm creating the `runAutolinkingConfig` task. This task is responsible of either: - Invoking the `npx react-native-community/cli config` command (or the one specified by the user) - Copying the config output file specified by the user (if any). The task re-executes only if any of the lockfile are actually changed otherwise it just returns as "UP-TO-DATE" This allows us to Changelog: [Internal] [Changed] - RNGP - Setup the RunAutolinkingConfigTask to run the config command Reviewed By: cipolleschi, blakef Differential Revision: D55475596 fbshipit-source-id: 3c687f965c59eb82fc447546ebd936ba401f34f2
1 parent 6262158 commit 1df1570

File tree

5 files changed

+261
-1
lines changed

5 files changed

+261
-1
lines changed

packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ abstract class ReactExtension @Inject constructor(project: Project) {
169169
.convention(listOf("npx", "@react-native-community/cli", "config"))
170170

171171
/**
172-
* Location of the lock files used to consider wether autolinking [autolinkConfigCommand] should
172+
* Location of the lock files used to consider whether autolinking [autolinkConfigCommand] should
173173
* re-execute or not. If file collection is unchanged, the autolinking command will not be
174174
* re-executed.
175175
*

packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.android.build.gradle.internal.tasks.factory.dependsOn
1212
import com.facebook.react.internal.PrivateReactExtension
1313
import com.facebook.react.tasks.GenerateCodegenArtifactsTask
1414
import com.facebook.react.tasks.GenerateCodegenSchemaTask
15+
import com.facebook.react.tasks.RunAutolinkingConfigTask
1516
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForApp
1617
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForLibraries
1718
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts
@@ -78,6 +79,7 @@ class ReactPlugin : Plugin<Project> {
7879
project.configureReactTasks(variant = variant, config = extension)
7980
}
8081
}
82+
configureAutolinking(project, extension)
8183
configureCodegen(project, extension, rootExtension, isLibrary = false)
8284
}
8385

@@ -209,4 +211,21 @@ class ReactPlugin : Plugin<Project> {
209211
// This will invoke the codegen before compiling the entire project.
210212
project.tasks.named("preBuild", Task::class.java).dependsOn(generateCodegenArtifactsTask)
211213
}
214+
215+
/** This function sets up Autolinking for App users */
216+
private fun configureAutolinking(
217+
project: Project,
218+
extension: ReactExtension,
219+
) {
220+
val generatedAutolinkingDir: Provider<Directory> =
221+
project.layout.buildDirectory.dir("generated/autolinking")
222+
val configOutputFile = generatedAutolinkingDir.get().file("config-output.json")
223+
224+
project.tasks.register("runAutolinkingConfig", RunAutolinkingConfigTask::class.java) { task ->
225+
task.autolinkConfigCommand.set(extension.autolinkConfigCommand)
226+
task.autolinkConfigFile.set(extension.autolinkConfigFile)
227+
task.autolinkOutputFile.set(configOutputFile)
228+
task.autolinkLockFiles.set(extension.autolinkLockFiles)
229+
}
230+
}
212231
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.tasks
9+
10+
import com.facebook.react.utils.windowsAwareCommandLine
11+
import java.io.FileOutputStream
12+
import org.gradle.api.file.FileCollection
13+
import org.gradle.api.file.RegularFileProperty
14+
import org.gradle.api.provider.ListProperty
15+
import org.gradle.api.provider.Property
16+
import org.gradle.api.tasks.*
17+
18+
/**
19+
* A task that will run @react-native-community/cli config if necessary to generate the autolinking
20+
* configuration file.
21+
*/
22+
abstract class RunAutolinkingConfigTask : Exec() {
23+
24+
init {
25+
group = "react"
26+
}
27+
28+
@get:Input abstract val autolinkConfigCommand: ListProperty<String>
29+
30+
/*
31+
* We don't want to re-run config if the lockfiles haven't changed.
32+
* So we have the lockfiles as @InputFiles for this task.
33+
*/
34+
@get:InputFiles abstract val autolinkLockFiles: Property<FileCollection>
35+
36+
@get:InputFile @get:Optional abstract val autolinkConfigFile: RegularFileProperty
37+
38+
@get:OutputFile abstract val autolinkOutputFile: RegularFileProperty
39+
40+
override fun exec() {
41+
wipeOutputDir()
42+
setupCommandLine()
43+
super.exec()
44+
}
45+
46+
internal fun setupCommandLine() {
47+
if (!autolinkConfigFile.isPresent || !autolinkConfigFile.get().asFile.exists()) {
48+
setupConfigCommandLine()
49+
} else {
50+
setupConfigCopyCommandLine()
51+
}
52+
}
53+
54+
internal fun wipeOutputDir() {
55+
autolinkOutputFile.asFile.get().apply {
56+
deleteRecursively()
57+
parentFile.mkdirs()
58+
}
59+
}
60+
61+
internal fun setupConfigCommandLine() {
62+
workingDir(project.projectDir)
63+
standardOutput = FileOutputStream(autolinkOutputFile.get().asFile)
64+
commandLine(
65+
windowsAwareCommandLine(
66+
*autolinkConfigCommand.get().toTypedArray(),
67+
))
68+
}
69+
70+
internal fun setupConfigCopyCommandLine() {
71+
workingDir(project.projectDir)
72+
commandLine(
73+
windowsAwareCommandLine(
74+
"cp",
75+
autolinkConfigFile.get().asFile.absolutePath,
76+
autolinkOutputFile.get().asFile.absolutePath))
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.tasks
9+
10+
import com.facebook.react.tests.createProject
11+
import com.facebook.react.tests.createTestTask
12+
import java.io.File
13+
import java.io.FileOutputStream
14+
import org.junit.Assert.assertEquals
15+
import org.junit.Assert.assertFalse
16+
import org.junit.Assert.assertTrue
17+
import org.junit.Rule
18+
import org.junit.Test
19+
import org.junit.rules.TemporaryFolder
20+
21+
class RunAutolinkingConfigTaskTest {
22+
23+
@get:Rule val tempFolder = TemporaryFolder()
24+
25+
@Test
26+
fun runAutolinkingConfigTask_groupIsSetCorrectly() {
27+
val task = createTestTask<BundleHermesCTask> {}
28+
assertEquals("react", task.group)
29+
}
30+
31+
@Test
32+
fun runAutolinkingConfigTask_staticInputs_areSetCorrectly() {
33+
val project = createProject()
34+
35+
val task =
36+
createTestTask<RunAutolinkingConfigTask> {
37+
it.autolinkConfigCommand.set(listOf("rm", "-rf", "/"))
38+
it.autolinkLockFiles.set(project.files("packager.lock", "another-packager.lock"))
39+
it.autolinkConfigFile.set(tempFolder.newFile("dependencies.json"))
40+
it.autolinkOutputFile.set(tempFolder.newFile("output.json"))
41+
}
42+
43+
assertEquals(3, task.inputs.files.files.size)
44+
task.autolinkLockFiles.get().files.forEach {
45+
assertTrue(
46+
it.name == "depedencies.json" ||
47+
it.name == "packager.lock" ||
48+
it.name == "another-packager.lock")
49+
}
50+
51+
assertTrue(task.inputs.properties.containsKey("autolinkConfigCommand"))
52+
assertEquals(1, task.outputs.files.files.size)
53+
assertEquals(File(tempFolder.root, "output.json"), task.outputs.files.singleFile)
54+
assertEquals(listOf("rm", "-rf", "/"), task.autolinkConfigCommand.get())
55+
56+
assertEquals(2, task.autolinkLockFiles.get().files.size)
57+
task.autolinkLockFiles.get().files.forEach {
58+
assertTrue(it.name == "packager.lock" || it.name == "another-packager.lock")
59+
}
60+
61+
assertEquals(File(tempFolder.root, "dependencies.json"), task.autolinkConfigFile.get().asFile)
62+
assertEquals(File(tempFolder.root, "output.json"), task.autolinkOutputFile.get().asFile)
63+
}
64+
65+
@Test
66+
fun wipeOutputDir_worksCorrectly() {
67+
val outputDir =
68+
tempFolder.newFolder("output").apply {
69+
File(this, "output.json").createNewFile()
70+
File(this, "NothingToSeeHere.java").createNewFile()
71+
}
72+
73+
val task = createTestTask<RunAutolinkingConfigTask> { it.autolinkOutputFile.set(outputDir) }
74+
task.wipeOutputDir()
75+
76+
assertFalse(outputDir.exists())
77+
}
78+
79+
@Test
80+
fun setupConfigCommandLine_worksCorrectly() {
81+
val project = createProject()
82+
83+
val task =
84+
createTestTask<RunAutolinkingConfigTask>(project) {
85+
it.autolinkConfigCommand.set(listOf("rm", "-rf", "/"))
86+
it.autolinkOutputFile.set(tempFolder.newFile("output.json"))
87+
}
88+
task.setupConfigCommandLine()
89+
90+
assertEquals(project.projectDir, task.workingDir)
91+
assertTrue(task.standardOutput is FileOutputStream)
92+
assertEquals(listOf("rm", "-rf", "/"), task.commandLine)
93+
}
94+
95+
@Test
96+
fun setupConfigCopyCommandLine_worksCorrectly() {
97+
val project = createProject()
98+
99+
val task =
100+
createTestTask<RunAutolinkingConfigTask>(project) {
101+
it.autolinkConfigFile.set(tempFolder.newFile("dependencies.json"))
102+
it.autolinkOutputFile.set(tempFolder.newFile("output.json"))
103+
}
104+
task.setupConfigCopyCommandLine()
105+
106+
assertEquals(project.projectDir, task.workingDir)
107+
assertTrue(task.standardOutput !is FileOutputStream)
108+
assertEquals("cp", task.commandLine[0])
109+
assertEquals(File(tempFolder.root, "dependencies.json").absolutePath, task.commandLine[1])
110+
assertEquals(File(tempFolder.root, "output.json").absolutePath, task.commandLine[2])
111+
}
112+
113+
@Test
114+
fun setupCommandLine_withoutAutolinkConfigFileConfigured_invokesCommand() {
115+
val project = createProject()
116+
117+
val task =
118+
createTestTask<RunAutolinkingConfigTask>(project) {
119+
it.autolinkConfigCommand.set(listOf("rm", "-rf", "/"))
120+
it.autolinkOutputFile.set(tempFolder.newFile("output.json"))
121+
}
122+
task.setupCommandLine()
123+
124+
assertEquals(listOf("rm", "-rf", "/"), task.commandLine)
125+
}
126+
127+
@Test
128+
fun setupCommandLine_withoutMissingConfigFile_invokesCommand() {
129+
val project = createProject()
130+
131+
val task =
132+
createTestTask<RunAutolinkingConfigTask>(project) {
133+
it.autolinkConfigCommand.set(listOf("rm", "-rf", "/"))
134+
it.autolinkConfigFile.set(File(tempFolder.root, "dependencies.json"))
135+
it.autolinkOutputFile.set(tempFolder.newFile("output.json"))
136+
}
137+
task.setupCommandLine()
138+
139+
assertEquals(listOf("rm", "-rf", "/"), task.commandLine)
140+
}
141+
142+
@Test
143+
fun setupCommandLine_withoutExistingConfigFile_invokesCp() {
144+
val project = createProject()
145+
val configFile = tempFolder.newFile("dependencies.json").apply { writeText("¯\\_(ツ)_/¯") }
146+
147+
val task =
148+
createTestTask<RunAutolinkingConfigTask>(project) {
149+
it.autolinkConfigCommand.set(listOf("rm", "-rf", "/"))
150+
it.autolinkConfigFile.set(configFile)
151+
it.autolinkOutputFile.set(tempFolder.newFile("output.json"))
152+
}
153+
task.setupCommandLine()
154+
155+
assertEquals(
156+
listOf("cp", configFile.absolutePath, File(tempFolder.root, "output.json").absolutePath),
157+
task.commandLine)
158+
}
159+
}

packages/rn-tester/android/app/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ react {
6161
// The hermes compiler command to run. By default it is 'hermesc'
6262
hermesCommand = "$reactNativeDirPath/ReactAndroid/hermes-engine/build/hermes/bin/hermesc"
6363
enableHermesOnlyInVariants = listOf("hermesDebug", "hermesRelease")
64+
65+
/* Autolinking */
66+
// The location of the monorepo lockfiles to `config` is cached correctly.
67+
autolinkLockFiles = files("$rootDir/yarn.lock")
6468
}
6569

6670
/** Run Proguard to shrink the Java bytecode in release builds. */

0 commit comments

Comments
 (0)