From 46fcc8eff93b29d9b17d163f6b2dd1fac37f2449 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 8 Oct 2025 00:00:48 +0530 Subject: [PATCH 01/16] Fix Lint --- .../test-library-on-nightly/action.yml | 18 +++ .../workflows/test-libraries-on-nightlies.yml | 1 + libraries.json | 8 ++ libraries.schema.json | 8 ++ patches/.gitkeep | 0 scripts/apply-patch.js | 110 ++++++++++++++++++ scripts/make-patch.js | 83 +++++++++++++ 7 files changed, 228 insertions(+) create mode 100644 patches/.gitkeep create mode 100755 scripts/apply-patch.js create mode 100755 scripts/make-patch.js diff --git a/.github/actions/test-library-on-nightly/action.yml b/.github/actions/test-library-on-nightly/action.yml index f108f69..5f27903 100644 --- a/.github/actions/test-library-on-nightly/action.yml +++ b/.github/actions/test-library-on-nightly/action.yml @@ -11,6 +11,10 @@ inputs: description: Number of retry attempts for failed operations required: false default: '3' + patch-file: + description: Optional path to a patch file to apply after installing the library + required: false + default: '' runs: using: composite steps: @@ -34,6 +38,20 @@ runs: cd /tmp/RNApp rm -rf node_modules yarn.lock || true yarn cache clean || true + + - name: Apply patch if specified + if: ${{ inputs.patch-file != '' }} + shell: bash + run: | + if [ -f "$GITHUB_WORKSPACE/${{ inputs.patch-file }}" ]; then + echo "Applying patch: ${{ inputs.patch-file }}" + cd /tmp/RNApp + node "$GITHUB_WORKSPACE/scripts/apply-patch.js" "$GITHUB_WORKSPACE/${{ inputs.patch-file }}" + echo "✅ Patch applied successfully" + else + echo "⚠️ Warning: Patch file not found: ${{ inputs.patch-file }}" + echo "Continuing without patch..." + fi # iOS - name: Setup xcode diff --git a/.github/workflows/test-libraries-on-nightlies.yml b/.github/workflows/test-libraries-on-nightlies.yml index c5cc921..61abc1f 100644 --- a/.github/workflows/test-libraries-on-nightlies.yml +++ b/.github/workflows/test-libraries-on-nightlies.yml @@ -58,6 +58,7 @@ jobs: with: library-npm-package: ${{ fromJSON(needs.runner-setup.outputs.library-data)[matrix.library].installCommand }} platform: ${{ matrix.platform }} + patch-file: ${{ fromJSON(needs.runner-setup.outputs.library-data)[matrix.library].patchFile || '' }} - name: Save outcome id: save-outcome if: always() diff --git a/libraries.json b/libraries.json index 85c518a..41ed7a5 100644 --- a/libraries.json +++ b/libraries.json @@ -365,5 +365,13 @@ "ios": true, "maintainersUsernames": [], "notes": "" + }, + "react-native-nitro-image": { + "description": "A high-performance image component for React Native", + "installCommand": "react-native-nitro-image", + "android": true, + "ios": true, + "maintainersUsernames": [], + "notes": "Test library for React Native Nitro Image" } } diff --git a/libraries.schema.json b/libraries.schema.json index f6199b2..21351a6 100644 --- a/libraries.schema.json +++ b/libraries.schema.json @@ -50,6 +50,14 @@ "Build currently broken due to X reason.", "One of top most used libraries according to the npm stats." ] + }, + "patchFile": { + "type": "string", + "description": "Optional path to a patch file (relative to repo root) to apply after installing the library but before building. Patch should be created using 'git diff --binary' format (e.g., using scripts/make-patch.js).", + "examples": [ + "patches/react-native-reanimated.patch", + "patches/library-name-fix.patch" + ] } }, "required": [ diff --git a/patches/.gitkeep b/patches/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/apply-patch.js b/scripts/apply-patch.js new file mode 100755 index 0000000..06aeca3 --- /dev/null +++ b/scripts/apply-patch.js @@ -0,0 +1,110 @@ +#!/usr/bin/env node +/** + * apply-patch.js + * Applies a patch created with `git diff --binary ...` (like our make-patch script). + * + * Usage: + * node apply-patch.js [--dry-run] [--reverse] [--reject] [--staged] [--no-3way] + * + * Flags: + * --dry-run : Don't change anything; just check if it would apply cleanly. + * --reverse : Apply the patch in reverse (i.e., undo it). + * --reject : On conflicts, write *.rej files (instead of failing fast). + * --staged : Apply to the index too (like `git apply --index`) so changes show up staged. + * --no-3way : Disable 3-way fallback; by default we use `--3way` for resilience. + */ + +const { spawnSync } = require("child_process"); +const fs = require("fs"); +const path = require("path"); + +function must(cmd, args, opts = {}) { + const res = spawnSync(cmd, args, { encoding: "utf8", ...opts }); + if (res.status !== 0) { + const msg = (res.stderr || res.stdout || "").trim(); + throw new Error(`${cmd} ${args.join(" ")}\n${msg}`); + } + return (res.stdout || "").trim(); +} + +function parseArgs() { + const argv = process.argv.slice(2); + let file = null; + const opts = { dryRun: false, reverse: false, reject: false, staged: false, threeWay: true }; + + for (const a of argv) { + if (!a.startsWith("--") && !file) file = a; + else if (a === "--dry-run") opts.dryRun = true; + else if (a === "--reverse") opts.reverse = true; + else if (a === "--reject") opts.reject = true; + else if (a === "--staged") opts.staged = true; + else if (a === "--no-3way") opts.threeWay = false; + else { + console.error(`Unrecognized argument: ${a}`); + process.exit(1); + } + } + if (!file) { + console.error("Usage: node apply-patch.js [--dry-run] [--reverse] [--reject] [--staged] [--no-3way]"); + process.exit(1); + } + return { file, opts }; +} + +try { + // 1) Basic checks + must("git", ["rev-parse", "--is-inside-work-tree"]); + const { file, opts } = parseArgs(); + + const patchPath = path.resolve(process.cwd(), file); + if (!fs.existsSync(patchPath)) { + console.error(`Patch not found: ${patchPath}`); + process.exit(1); + } + + // 2) Build `git apply` args (pass as array => no shell quoting issues) + const args = ["apply", "--binary", "--whitespace=nowarn"]; + if (opts.threeWay) args.push("--3way"); // try 3-way merge using index as base + if (opts.dryRun) args.push("--check"); // check only + if (opts.reverse) args.push("--reverse"); // reverse apply + if (opts.reject) args.push("--reject"); // write *.rej on failed hunks + if (opts.staged) args.push("--index"); // update the index (stage changes) + + args.push(patchPath); + + // 3) Apply + const res = spawnSync("git", args, { encoding: "utf8" }); + + if (res.status !== 0) { + // Helpful hints for common failure modes + const stderr = (res.stderr || res.stdout || "").trim(); + console.error("Failed to apply patch.\n"); + console.error(stderr); + + // If 3-way was enabled and we still failed, suggest trying without it or with reverse + if (opts.threeWay && !opts.dryRun) { + console.error("\nTips:"); + console.error(" • If the patch was made from a different base, try: --no-3way"); + console.error(" • If you're undoing a previous apply, try: --reverse"); + console.error(" • To see where it fails without changing files, use: --dry-run"); + console.error(" • To keep partial results and .rej files, add: --reject"); + } + process.exit(res.status || 1); + } + + // 4) Success + if (opts.dryRun) { + console.log("✅ Dry run successful: patch would apply cleanly."); + } else { + console.log("✅ Patch applied successfully."); + if (opts.staged) { + console.log(" Changes are staged (used --staged)."); + } else { + console.log(" Changes are in your working tree (not staged)."); + } + } + +} catch (err) { + console.error("Unexpected error:\n" + err.message); + process.exit(1); +} diff --git a/scripts/make-patch.js b/scripts/make-patch.js new file mode 100755 index 0000000..bca30bc --- /dev/null +++ b/scripts/make-patch.js @@ -0,0 +1,83 @@ +#!/usr/bin/env node +/** + * make-patch.js + * Generates a patch of staged + unstaged changes, including NEW files, + * excluding this script and any extra --exclude patterns. + */ + +const { spawnSync } = require("child_process"); +const fs = require("fs"); +const path = require("path"); + +function ts() { + const d = new Date(), p = n => String(n).padStart(2, "0"); + return `patch-${d.getFullYear()}${p(d.getMonth()+1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}.patch`; +} + +function must(cmd, args, opts = {}) { + const res = spawnSync(cmd, args, { encoding: "utf8", ...opts }); + if (res.status !== 0) { + const msg = (res.stderr || res.stdout || "").trim(); + throw new Error(`${cmd} ${args.join(" ")}\n${msg}`); + } + return res.stdout.trim(); +} + +// Parse args +const argv = process.argv.slice(2); +let outName = null; +const excludes = []; +for (let i = 0; i < argv.length; i++) { + const a = argv[i]; + if (a === "--exclude") { + excludes.push(argv[++i] ?? ""); + } else if (a.startsWith("--exclude=")) { + excludes.push(a.slice("--exclude=".length)); + } else if (!outName) { + outName = a; + } else { + console.error(`Unrecognized argument: ${a}`); + process.exit(1); + } +} + +try { + // Ensure we’re in a repo and get root + must("git", ["rev-parse", "--is-inside-work-tree"]); + const toplevel = must("git", ["rev-parse", "--show-toplevel"]); + + // Make untracked files appear in diff without staging content + spawnSync("git", ["add", "-N", "."], { stdio: "ignore" }); + + // Build pathspecs + const relSelf = path + .relative(toplevel, path.resolve(process.argv[1])) + .split(path.sep) + .join("/"); + + const pathspecs = [ + ".", // start at repo root + `:(exclude)${relSelf}`, // exclude this script + ...excludes.map(p => `:(exclude)${p.replace(/\\/g, "/")}`), + ]; + + // Run: git diff --binary HEAD -- + const args = ["diff", "--binary", "HEAD", "--", ...pathspecs]; + const diff = must("git", args, { maxBuffer: 1024 * 1024 * 100 }); // 100MB buffer + + if (!diff) { + console.log("No changes found (after exclusions). Nothing to write."); + process.exit(0); + } + + const filename = (outName && outName.trim()) || ts(); + const outPath = path.resolve(process.cwd(), filename); + fs.writeFileSync(outPath, diff, "utf8"); + + console.log(`Patch written: ${outPath}`); + console.log(`Apply with: git apply ${JSON.stringify(filename)}`); + console.log("Excluded:", [relSelf, ...excludes].join(", ")); +} catch (err) { + console.error("Unexpected error:\n" + err.message); + process.exit(1); +} From d4c9019a71258a30a03466d5028e6f61fca701b5 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 8 Oct 2025 00:02:32 +0530 Subject: [PATCH 02/16] This will be probably run --- .github/workflows/check-nightly.yml | 1 - .../workflows/test-libraries-on-nightlies.yml | 23 ------------------- 2 files changed, 24 deletions(-) diff --git a/.github/workflows/check-nightly.yml b/.github/workflows/check-nightly.yml index f9ec4f5..7913eb2 100644 --- a/.github/workflows/check-nightly.yml +++ b/.github/workflows/check-nightly.yml @@ -21,7 +21,6 @@ concurrency: jobs: check-nightly: runs-on: ubuntu-latest - if: github.repository == 'react-native-community/nightly-tests' steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/test-libraries-on-nightlies.yml b/.github/workflows/test-libraries-on-nightlies.yml index 61abc1f..3113c04 100644 --- a/.github/workflows/test-libraries-on-nightlies.yml +++ b/.github/workflows/test-libraries-on-nightlies.yml @@ -72,26 +72,3 @@ jobs: with: name: ${{ steps.save-outcome.outputs.lib_folder }}-${{ matrix.platform }}-outcome path: /tmp/${{ steps.save-outcome.outputs.lib_folder }}-${{ matrix.platform }}-outcome - - collect-results: - runs-on: ubuntu-latest - needs: [test-library-on-nightly] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Restore outcomes - uses: actions/download-artifact@v4 - with: - pattern: '*-outcome' - path: /tmp - - name: Collect failures - uses: actions/github-script@v6 - env: - FIREBASE_APP_EMAIL: ${{ secrets.firebase_app_email }} - FIREBASE_APP_PASS: ${{ secrets.firebase_app_pass }} - FIREBASE_APP_APIKEY: ${{ secrets.firebase_app_apikey }} - FIREBASE_APP_PROJECTNAME: ${{ secrets.firebase_app_projectname }} - with: - script: | - const {collectResults} = require('./.github/workflow-scripts/collectNightlyOutcomes.js'); - await collectResults('${{secrets.discord_webhook_url}}'); From 83ac7ddd1fc96efcfacc32c26d31f80284f80723 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 8 Oct 2025 00:26:54 +0530 Subject: [PATCH 03/16] This will be probably run --- libraries.json | 3 ++- patches/nitro-image.patch | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 patches/nitro-image.patch diff --git a/libraries.json b/libraries.json index 41ed7a5..d31e356 100644 --- a/libraries.json +++ b/libraries.json @@ -372,6 +372,7 @@ "android": true, "ios": true, "maintainersUsernames": [], - "notes": "Test library for React Native Nitro Image" + "notes": "Test library for React Native Nitro Image", + "patchFile": "patches/nitro-image.patch" } } diff --git a/patches/nitro-image.patch b/patches/nitro-image.patch new file mode 100644 index 0000000..10b7660 --- /dev/null +++ b/patches/nitro-image.patch @@ -0,0 +1,36 @@ +diff --git a/ios/Podfile b/ios/Podfile +index 319ed7b..fc92314 100644 +--- a/ios/Podfile ++++ b/ios/Podfile +@@ -16,6 +16,7 @@ end + + target 'FindMeiphone' do + config = use_native_modules! ++ pod 'SDWebImage', :modular_headers => true + + use_react_native!( + :path => config[:reactNativePath], +diff --git a/package.json b/package.json +index 2c66697..8fdbd91 100644 +--- a/package.json ++++ b/package.json +@@ -10,9 +10,11 @@ + "test": "jest" + }, + "dependencies": { ++ "@react-native/new-app-screen": "0.81.0", + "react": "19.1.0", + "react-native": "0.81.0", +- "@react-native/new-app-screen": "0.81.0", ++ "react-native-nitro-image": "^0.6.1", ++ "react-native-nitro-modules": "^0.29.8", + "react-native-safe-area-context": "^5.5.2" + }, + "devDependencies": { +@@ -38,4 +40,4 @@ + "engines": { + "node": ">=18" + } +-} +\ No newline at end of file ++} \ No newline at end of file From 65f6cc37af6e42a3b686caed0f7669d6850c5f85 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 8 Oct 2025 00:48:42 +0530 Subject: [PATCH 04/16] This will be probably run --- patches/nitro-image.patch | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/patches/nitro-image.patch b/patches/nitro-image.patch index 10b7660..30f62a8 100644 --- a/patches/nitro-image.patch +++ b/patches/nitro-image.patch @@ -11,7 +11,7 @@ index 319ed7b..fc92314 100644 use_react_native!( :path => config[:reactNativePath], diff --git a/package.json b/package.json -index 2c66697..8fdbd91 100644 +index 2c66697..2bacf73 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,11 @@ @@ -26,11 +26,4 @@ index 2c66697..8fdbd91 100644 + "react-native-nitro-modules": "^0.29.8", "react-native-safe-area-context": "^5.5.2" }, - "devDependencies": { -@@ -38,4 +40,4 @@ - "engines": { - "node": ">=18" - } --} -\ No newline at end of file -+} \ No newline at end of file + "devDependencies": { \ No newline at end of file From 4efd222b72d5e2e43ea1eb45c95fdd0008fac857 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 8 Oct 2025 00:48:59 +0530 Subject: [PATCH 05/16] This will be probably run --- libraries.json | 359 ------------------------------------------------- 1 file changed, 359 deletions(-) diff --git a/libraries.json b/libraries.json index d31e356..2f8e1e4 100644 --- a/libraries.json +++ b/libraries.json @@ -7,365 +7,6 @@ "maintainersUsernames": [], "notes": "" }, - "react-native-blob-util": { - "description": "A module provides upload, download, and files access API", - "installCommand": "react-native-blob-util", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "@react-native-clipboard/clipboard": { - "description": "React Native Clipboard API for iOS and Android", - "installCommand": "@react-native-clipboard/clipboard", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "@react-native-community/datetimepicker": { - "description": "React Native date & time picker component for iOS, Android and Windows", - "installCommand": "@react-native-community/datetimepicker", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-gesture-handler": { - "description": "Declarative API exposing platform native touch and gesture system to React Native", - "installCommand": "react-native-gesture-handler", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-image-picker": { - "description": "A React Native module that allows you to use native UI to select media from the device library or directly from the camera", - "installCommand": "react-native-image-picker", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-linear-gradient": { - "description": "A component for react-native", - "installCommand": "react-native-linear-gradient", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "@react-native-masked-view/masked-view": { - "description": "React Native MaskedView component", - "installCommand": "@react-native-masked-view/masked-view", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "@react-native-community/netinfo": { - "description": "React Native Network Info API for iOS & Android", - "installCommand": "@react-native-community/netinfo", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-reanimated": { - "description": "React Native's Animated library reimplemented", - "installCommand": "react-native-reanimated@nightly react-native-worklets@nightly", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-worklets": { - "description": "Powerful multithreading engine", - "installCommand": "react-native-worklets@nightly", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-svg": { - "description": "SVG library for React Native, React Native Web, and plain React web projects", - "installCommand": "react-native-svg", - "android": true, - "ios": true, - "maintainersUsernames": [], - "notes": "" - }, - "react-native-video": { - "description": "A