Skip to content

Commit 5d8bc02

Browse files
committed
ci: add workflow to test building local libraries
1 parent 499d822 commit 5d8bc02

7 files changed

Lines changed: 265 additions & 12 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
name: Build local libraries
2+
on:
3+
workflow_dispatch:
4+
schedule:
5+
- cron: "0 0 * * *"
6+
push:
7+
branches:
8+
- main
9+
- next
10+
pull_request:
11+
branches:
12+
- main
13+
- next
14+
merge_group:
15+
types:
16+
- checks_requested
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
build:
23+
env:
24+
XCODE_VERSION: 26
25+
RCT_REMOVE_LEGACY_ARCH: 1
26+
RCT_USE_RN_DEP: 1
27+
RCT_USE_PREBUILT_RNCORE: 1
28+
REACT_NATIVE_VERSION: 0.85.0
29+
EXPO_SDK_VERSION: 55
30+
APP_NAME: LocalLibraryApp
31+
LIBRARY_NAME: TestLibrary
32+
LIBRARY_DIR: modules/TestLibrary
33+
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
os:
38+
- ubuntu-latest
39+
- macos-15
40+
app:
41+
- community-cli
42+
- expo
43+
type:
44+
- name: turbo-module
45+
language: kotlin-objc
46+
- name: nitro-module
47+
language: kotlin-swift
48+
49+
concurrency:
50+
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.os }}-${{ matrix.app }}-${{ matrix.type.name }}-${{ matrix.type.language }}
51+
cancel-in-progress: true
52+
53+
runs-on: ${{ matrix.os }}
54+
55+
steps:
56+
- name: Checkout
57+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
58+
59+
- name: Setup
60+
uses: ./.github/actions/setup
61+
62+
- name: Build package
63+
run: |
64+
yarn workspace create-react-native-library prepare
65+
66+
- name: Create app
67+
shell: bash
68+
run: |
69+
if [[ "${{ matrix.app }}" == "community-cli" ]]; then
70+
npx @react-native-community/cli init "$APP_NAME" \
71+
--directory "$APP_NAME" \
72+
--version "$REACT_NATIVE_VERSION" \
73+
--skip-install \
74+
--skip-git-init \
75+
--pm npm \
76+
--package-name com.locallibraryapp
77+
else
78+
npx create-expo-app@latest "$APP_NAME" \
79+
--no-install \
80+
--template "blank@sdk-$EXPO_SDK_VERSION"
81+
fi
82+
83+
- name: Create local library
84+
working-directory: ${{ env.APP_NAME }}
85+
shell: bash
86+
run: |
87+
../packages/create-react-native-library/bin/create-react-native-library "$LIBRARY_NAME" \
88+
--local \
89+
--directory "$LIBRARY_DIR" \
90+
--slug @bob/react-native-test \
91+
--description test \
92+
--type ${{ matrix.type.name }} \
93+
--languages ${{ matrix.type.language }}
94+
95+
- name: Restore dependencies of app
96+
id: app-npm-cache
97+
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
98+
with:
99+
path: |
100+
${{ env.APP_NAME }}/node_modules
101+
${{ env.APP_NAME }}/package-lock.json
102+
key: ${{ runner.os }}-local-library-npm-${{ matrix.app }}-${{ matrix.type.name }}-${{ matrix.type.language }}-${{ hashFiles(format('{0}/package.json', env.APP_NAME), format('{0}/modules/**/package.json', env.APP_NAME)) }}
103+
restore-keys: |
104+
${{ runner.os }}-local-library-npm-${{ matrix.app }}-${{ matrix.type.name }}-${{ matrix.type.language }}-
105+
${{ runner.os }}-local-library-npm-${{ matrix.app }}-
106+
107+
- name: Install dependencies of app
108+
if: steps.app-npm-cache.outputs.cache-hit != 'true'
109+
working-directory: ${{ env.APP_NAME }}
110+
run: |
111+
npm install --no-audit --no-fund
112+
113+
- name: Cache dependencies of app
114+
if: steps.app-npm-cache.outputs.cache-hit != 'true'
115+
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
116+
with:
117+
path: |
118+
${{ env.APP_NAME }}/node_modules
119+
${{ env.APP_NAME }}/package-lock.json
120+
key: ${{ steps.app-npm-cache.outputs.cache-primary-key }}
121+
122+
- name: Generate nitrogen code
123+
if: matrix.type.name == 'nitro-module'
124+
working-directory: ${{ env.APP_NAME }}/${{ env.LIBRARY_DIR }}
125+
shell: bash
126+
run: |
127+
nitro_version=$(node -p "require('../../package.json').dependencies['react-native-nitro-modules']")
128+
npm exec --yes --package "nitrogen@$nitro_version" -- nitrogen
129+
130+
- name: Install JDK
131+
if: runner.os == 'Linux'
132+
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
133+
with:
134+
distribution: 'zulu'
135+
java-version: '17'
136+
137+
- name: Finalize Android SDK
138+
if: runner.os == 'Linux'
139+
run: |
140+
/bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null"
141+
142+
- name: Prebuild Expo app (Android)
143+
if: runner.os == 'Linux' && matrix.app == 'expo'
144+
working-directory: ${{ env.APP_NAME }}
145+
run: |
146+
npx expo prebuild --platform android --non-interactive
147+
148+
- name: Cache Gradle
149+
if: runner.os == 'Linux'
150+
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
151+
with:
152+
path: |
153+
~/.gradle/wrapper
154+
~/.gradle/caches
155+
key: ${{ runner.os }}-local-library-gradle-${{ matrix.app }}-${{ hashFiles(format('{0}/android/gradle/wrapper/gradle-wrapper.properties', env.APP_NAME)) }}
156+
restore-keys: |
157+
${{ runner.os }}-local-library-gradle-${{ matrix.app }}-
158+
${{ runner.os }}-local-library-gradle-
159+
160+
- name: Build app (Android)
161+
if: runner.os == 'Linux'
162+
working-directory: ${{ env.APP_NAME }}
163+
shell: bash
164+
env:
165+
JAVA_OPTS: "-XX:MaxHeapSize=6g"
166+
run: |
167+
if [[ "${{ matrix.app }}" == "community-cli" ]]; then
168+
npx react-native build-android --extra-params "--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a"
169+
else
170+
cd android
171+
./gradlew assembleDebug -DtestBuildType=debug -Dorg.gradle.jvmargs=-Xmx4g -PreactNativeArchitectures=arm64-v8a --no-daemon --console=plain
172+
fi
173+
174+
- name: Use appropriate Xcode version
175+
if: runner.os == 'macOS'
176+
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
177+
with:
178+
xcode-version: ${{ env.XCODE_VERSION }}
179+
180+
- name: Prebuild Expo app (iOS)
181+
if: runner.os == 'macOS' && matrix.app == 'expo'
182+
working-directory: ${{ env.APP_NAME }}
183+
run: |
184+
npx expo prebuild --platform ios --non-interactive
185+
186+
- name: Install cocoapods
187+
if: runner.os == 'macOS'
188+
working-directory: ${{ env.APP_NAME }}
189+
shell: bash
190+
run: |
191+
if [[ -f Gemfile ]]; then
192+
bundle install
193+
bundle exec pod repo update --verbose
194+
bundle exec pod install --project-directory=ios
195+
else
196+
pod repo update --verbose
197+
pod install --project-directory=ios
198+
fi
199+
200+
- name: Build app (iOS)
201+
if: runner.os == 'macOS'
202+
working-directory: ${{ env.APP_NAME }}
203+
shell: bash
204+
run: |
205+
if [[ "${{ matrix.app }}" == "community-cli" ]]; then
206+
npx react-native build-ios --mode Debug
207+
else
208+
xcodebuild ONLY_ACTIVE_ARCH=YES \
209+
-workspace "ios/$APP_NAME.xcworkspace" \
210+
-UseNewBuildSystem=YES \
211+
-scheme "$APP_NAME" \
212+
-configuration Debug \
213+
-sdk iphonesimulator \
214+
-derivedDataPath ios/build \
215+
-quiet
216+
fi

.github/workflows/build-templates.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ on:
1515
types:
1616
- checks_requested
1717

18+
permissions:
19+
contents: read
20+
1821
jobs:
1922
build:
2023
env:

packages/create-react-native-library/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"github-username": "^9.0.0",
5252
"kleur": "^4.1.5",
5353
"ora": "^9.3.0",
54-
"pigment": "^0.4.4",
54+
"pigment": "^0.4.5",
5555
"typescript": "^6.0.3",
5656
"validate-npm-package-name": "^7.0.2"
5757
},

packages/create-react-native-library/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ async function create() {
4848

4949
console.log(''); // Empty new line after prompts
5050

51+
if (answers.directory == null) {
52+
throw new Error('Missing required option: --directory');
53+
}
54+
5155
const bobVersion = await bobVersionPromise;
5256
const nitroModulesVersion =
5357
answers.type === 'nitro-module' || answers.type === 'nitro-view'
@@ -101,7 +105,7 @@ async function create() {
101105
spinner.text = 'Configuring tools';
102106

103107
await configureTools({
104-
tools: answers.tools,
108+
tools: config.tools,
105109
config,
106110
root: folder,
107111
packageJson: rootPackageJson,

packages/create-react-native-library/src/prompt.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ export const prompt = create(['[name]'], {
172172
return answers.name;
173173
},
174174
validate: validateDirectory,
175+
required: true,
175176
skip: () => {
176177
const answers = prompt.read();
177178

@@ -261,6 +262,7 @@ export const prompt = create(['[name]'], {
261262
message: 'What is the name of the package author?',
262263
default: async () => getGitConfig('user.name'),
263264
validate: (input) => Boolean(input) || 'Cannot be empty',
265+
required: true,
264266
skip: (): boolean => prompt.read().local === true,
265267
},
266268
authorEmail: {
@@ -270,6 +272,7 @@ export const prompt = create(['[name]'], {
270272
default: async () => getGitConfig('user.email'),
271273
validate: (input) =>
272274
/^\S+@\S+$/.test(input) || 'Must be a valid email address',
275+
required: true,
273276
skip: (): boolean => prompt.read().local === true,
274277
},
275278
authorUrl: {
@@ -296,6 +299,7 @@ export const prompt = create(['[name]'], {
296299
return undefined;
297300
},
298301
validate: (input) => /^https?:\/\//.test(input) || 'Must be a valid URL',
302+
required: true,
299303
skip: (): boolean => prompt.read().local === true,
300304
},
301305
repoUrl: {
@@ -318,6 +322,7 @@ export const prompt = create(['[name]'], {
318322
return undefined;
319323
},
320324
validate: (input) => /^https?:\/\//.test(input) || 'Must be a valid URL',
325+
required: true,
321326
skip: (): boolean => prompt.read().local === true,
322327
},
323328
type: {

packages/create-react-native-library/src/template.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,31 @@ export function generateTemplateConfiguration({
151151
}): TemplateConfiguration {
152152
const { slug, languages, type } = answers;
153153

154+
let { authorName, authorEmail, authorUrl, repoUrl } = answers;
155+
156+
if (answers.local) {
157+
authorName = '';
158+
authorEmail = '';
159+
authorUrl = '';
160+
repoUrl = '';
161+
} else {
162+
if (authorName == null) {
163+
throw new Error('Missing required option: --author-name');
164+
}
165+
166+
if (authorEmail == null) {
167+
throw new Error('Missing required option: --author-email');
168+
}
169+
170+
if (authorUrl == null) {
171+
throw new Error('Missing required option: --author-url');
172+
}
173+
174+
if (repoUrl == null) {
175+
throw new Error('Missing required option: --repo-url');
176+
}
177+
}
178+
154179
const project = slug.replace(/^(react-native-|@[^/]+\/)/, '');
155180
let namespace: string | undefined;
156181

@@ -190,13 +215,13 @@ export function generateTemplateConfiguration({
190215
moduleConfig: getModuleConfig(type),
191216
},
192217
author: {
193-
name: answers.authorName,
194-
email: answers.authorEmail,
195-
url: answers.authorUrl,
218+
name: authorName,
219+
email: authorEmail,
220+
url: authorUrl,
196221
},
197-
repo: answers.repoUrl,
222+
repo: repoUrl,
198223
example: answers.example,
199-
tools: answers.tools,
224+
tools: answers.tools ?? [],
200225
year: new Date().getFullYear(),
201226
};
202227
}

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5347,7 +5347,7 @@ __metadata:
53475347
github-username: "npm:^9.0.0"
53485348
kleur: "npm:^4.1.5"
53495349
ora: "npm:^9.3.0"
5350-
pigment: "npm:^0.4.4"
5350+
pigment: "npm:^0.4.5"
53515351
typescript: "npm:^6.0.3"
53525352
validate-npm-package-name: "npm:^7.0.2"
53535353
bin:
@@ -10105,13 +10105,13 @@ __metadata:
1010510105
languageName: node
1010610106
linkType: hard
1010710107

10108-
"pigment@npm:^0.4.4":
10109-
version: 0.4.4
10110-
resolution: "pigment@npm:0.4.4"
10108+
"pigment@npm:^0.4.5":
10109+
version: 0.4.5
10110+
resolution: "pigment@npm:0.4.5"
1011110111
dependencies:
1011210112
ansi-escapes: "npm:^7.2.0"
1011310113
wrap-ansi: "npm:^9.0.2"
10114-
checksum: 10c0/d2663d4e44603ed4bdab7b1c7c73c0c8a42390599c7f7f880dc91b2cb00f252667e9e22606ca7c56db6bd36e4a6067e68141afd17d1e7d03867da8866bde5bb0
10114+
checksum: 10c0/696ba9feee6f22d59de62a37e31ced40845dc061c78175b18805eb9550215685e5fd6612e355025742152d8bc093b56ef258044e5dae7265d781cd2b353b3aac
1011510115
languageName: node
1011610116
linkType: hard
1011710117

0 commit comments

Comments
 (0)