Skip to content

Commit

Permalink
feat: automatically copy codegen artifacts to paper (#2933)
Browse files Browse the repository at this point in the history
## Description

Sibling of [similar task from
screens](software-mansion/react-native-screens#2168).
When changing native props on Fabric, codegen generates corresponding
interfaces and delegates. To make sure both implementations are
consistent, we implement those interfaces on Paper too. Currently, after
generating interfaces using codegen, developer needs to copy
corresponding files for paper manually. This task adds Gradle task, that
automates this.

## Changes

Add new task to build Gradle and necessary properties: 
- codegen artifacts dir and paper dir 
- flag in both fabric apps that indicates that copying should be
performed (we do want this task to be performed only when developing the
library)

## Test code and steps to reproduce

Remove `enabled` from
`src/specs/RNGestureHandlerButtonNativeComponent.ts` and run ` ./gradlew
generateCodegenArtifactsFromSchema` in `./FabricExample/android`. That
should automatically copy regenerated files to paper directory.

---------

Co-authored-by: Jakub Piasecki <jakub.piasecki@swmansion.com>
  • Loading branch information
maciekstosio and j-piasecki authored Jun 10, 2024
1 parent 2b0425b commit 50dfe9a
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 8 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/check-paper-integrity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Test Paper Architecture integrity
on: [pull_request]
jobs:
check:
if: github.repository == 'software-mansion/react-native-gesture-handler'
runs-on: ubuntu-latest
concurrency:
group: kotlin-lint-${{ github.ref }}
cancel-in-progress: true
steps:
- name: checkout
uses: actions/checkout@v2

- name: Use Java 17
uses: actions/setup-java@v3
with:
distribution: 'oracle'
java-version: '17'

- name: Use Node.js 18
uses: actions/setup-node@v2
with:
node-version: 18
cache: 'yarn'

- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- name: Install node dependencies
run: yarn install --frozen-lockfile

- name: Install node dependencies of FabricExample
run: (cd FabricExample && yarn install --frozen-lockfile)

- name: Restore build from cache
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
android/build
android/.gradle
key: ${{ runner.os }}-kotlin-lint-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'android/build.gradle') }}

- name: Check old arch integrity
run: yarn checkIntegrity
2 changes: 2 additions & 0 deletions FabricExample/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true

isGHExampleApp=true
105 changes: 105 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,108 @@ dependencies {
implementation "androidx.core:core-ktx:1.6.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

def isGHExampleApp() {
return project.hasProperty('isGHExampleApp') && project.property('isGHExampleApp') == "true"
}

def getAbsoluteCodegenArtifactsPaperDestination() {
if (!project.hasProperty('codegenArtifactsPaperDestination')) {
throw new Exception('[react-native-gesture-handler] Please fill codegenArtifactsPaperDestination variable in android/gradle.properties to point to the correct path to generated specs for paper')
}

return "${project.rootDir}/../../${project.property('codegenArtifactsPaperDestination')}"
}

def getAbsoluteCodegenArtifactsSource() {
if (!project.hasProperty('codegenArtifactsSource')) {
throw new Exception('[react-native-gesture-handler] Please fill codegenArtifactsSource variable in android/gradle.properties to point to the correct path to codegenerated artifacts')
}

return "${project.rootDir}/../../${project.property('codegenArtifactsSource')}"
}


tasks.register('copyCodegenArtifacts') {
group 'After build tasks'
description 'Task which copies codegen artifacts to paper architecture'

if (!isGHExampleApp() || !isNewArchitectureEnabled()) {
return
}

dependsOn tasks.generateCodegenArtifactsFromSchema

doLast {

def absoluteCodegenArtifactsPaperDestination = getAbsoluteCodegenArtifactsPaperDestination()
def absoluteCodegenArtifactsSource = getAbsoluteCodegenArtifactsSource()

def existingFiles = fileTree(absoluteCodegenArtifactsPaperDestination).matching {
include '**/*.java'
}

def generatedFiles = fileTree(absoluteCodegenArtifactsSource).matching {
include '**/*.java'
}

def existingFilesMap = [:]

existingFiles.forEach { existingFile ->
println existingFile
existingFilesMap[existingFile.name] = 1
}

generatedFiles.forEach { generatedFile ->
if (!existingFilesMap.containsKey(generatedFile.name)) {
logger.warn("[react-native-gesture-handler] ${generatedFile.name} not found in paper dir, if it's used on Android you need to copy it manually and implement yourself before using auto-copy feature.")
}
}

if (existingFiles.size() == 0) {
logger.warn("[react-native-gesture-handler] Paper destination with codegen interfaces is empty. This might be okay if you don't have any interfaces/delegates used on Android, but if that's not the case please check if codegenArtifactsPaperDestination property in android/gradle.properties is correct.")
}

existingFiles.forEach { existingFile ->
def generatedFile = new File("${absoluteCodegenArtifactsSource}/${existingFile.name}")

if (!generatedFile.exists()) {
logger.warn("[react-native-gesture-handler] ${existingFile.name} file does not exist in codegen artifacts source destination. Please check if you still need this interface/delagete.")
}
}

copy {
from absoluteCodegenArtifactsSource
include existingFiles.collect { it.name }
into absoluteCodegenArtifactsPaperDestination
}
}
}

if (isGHExampleApp() && isNewArchitectureEnabled() && !project.hasProperty('skipCodegenCopyTask')) {
tasks.generateCodegenArtifactsFromSchema.finalizedBy('copyCodegenArtifacts')
}

tasks.register('checkIntegrityBetweenArchitectures') {
group 'Verification tasks'
description 'Task to check integrity between fabric and paper architecture in terms of codegen generated interfaces/delegates'

if (isGHExampleApp()) {
return
}

def absoluteCodegenArtifactsPaperDestination = "../${project.property('codegenArtifactsPaperDestination')}"
def absoluteCodegenArtifactsSource = "../${project.property('codegenArtifactsSource')}"

def existingFiles = fileTree(absoluteCodegenArtifactsPaperDestination).matching {
include '**/*.java'
}

existingFiles.forEach { existingFile ->
def generatedFile = new File("${absoluteCodegenArtifactsSource}/${existingFile.name}")

if (existingFile.text != generatedFile.text) {
throw new RuntimeException("[react-native-gesture-handler] The source of ${existingFile.name} does not match with the one generated by codegen. Please check if you commited changes produced by copyCodegenArtifacts task.")
}
}
}
7 changes: 7 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemor
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
RNGH_kotlinVersion=1.6.21

# Path to codegen output directory with this library view managers' interfaces & delegates. Used by `copyCodegenArtifacts` task that helps to synchronize newly generated files with their Paper counterparts.
codegenArtifactsSource=android/build/generated/source/codegen/java/com/facebook/react/viewmanagers

# Path to directory with view managers' interfaces & delegates used while running on Paper architecture. This property is used as the output path for `copyCodegenArtifacts` task.
# Used by copyCodegenArtifacts task that automates copying those interfaces/delegates after codegen is run.
codegenArtifactsPaperDestination=android/paper/src/main/java/com/facebook/react/viewmanagers
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/

package com.facebook.react.viewmanagers;

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"format:ios": "find apple/ -iname *.h -o -iname *.m -o -iname *.cpp -o -iname *.mm | xargs clang-format -i",
"lint:js": "eslint --ext '.js,.ts,.tsx' src/ example/src FabricExample/src MacOSExample/src && yarn prettier --check './{src,example,FabricExample,MacOSExample}/**/*.{js,jsx,ts,tsx}'",
"lint:js-root": "eslint --ext '.js,.ts,.tsx' src/ && yarn prettier --check './src/**/*.{js,jsx,ts,tsx}'",
"lint:android": "./android/gradlew -p android spotlessCheck -q"
"lint:android": "./android/gradlew -p android spotlessCheck -q",
"checkIntegrity": "(cd ./FabricExample/android && ./gradlew generateCodegenArtifactsFromSchema -PskipCodegenCopyTask) && (cd ./android && ./gradlew checkIntegrityBetweenArchitectures)"
},
"react-native": "src/index.ts",
"main": "lib/commonjs/index.js",
Expand Down

0 comments on commit 50dfe9a

Please sign in to comment.