@ahmedsamirelsaka/react-native-local-release 2.0.0-rc.1

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/CREDENTIALS.md +79 -0
  3. package/LICENSE +21 -0
  4. package/README.md +112 -0
  5. package/SECURITY.md +44 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +326 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/config.d.ts +27 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +229 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/credentials.d.ts +27 -0
  15. package/dist/credentials.d.ts.map +1 -0
  16. package/dist/credentials.js +317 -0
  17. package/dist/credentials.js.map +1 -0
  18. package/dist/detect.d.ts +7 -0
  19. package/dist/detect.d.ts.map +1 -0
  20. package/dist/detect.js +326 -0
  21. package/dist/detect.js.map +1 -0
  22. package/dist/fs.d.ts +15 -0
  23. package/dist/fs.d.ts.map +1 -0
  24. package/dist/fs.js +79 -0
  25. package/dist/fs.js.map +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +6 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/install.d.ts +5 -0
  31. package/dist/install.d.ts.map +1 -0
  32. package/dist/install.js +338 -0
  33. package/dist/install.js.map +1 -0
  34. package/dist/logging.d.ts +15 -0
  35. package/dist/logging.d.ts.map +1 -0
  36. package/dist/logging.js +84 -0
  37. package/dist/logging.js.map +1 -0
  38. package/dist/patch.d.ts +39 -0
  39. package/dist/patch.d.ts.map +1 -0
  40. package/dist/patch.js +352 -0
  41. package/dist/patch.js.map +1 -0
  42. package/dist/paths.d.ts +14 -0
  43. package/dist/paths.d.ts.map +1 -0
  44. package/dist/paths.js +65 -0
  45. package/dist/paths.js.map +1 -0
  46. package/dist/process.d.ts +26 -0
  47. package/dist/process.d.ts.map +1 -0
  48. package/dist/process.js +43 -0
  49. package/dist/process.js.map +1 -0
  50. package/dist/prompt.d.ts +9 -0
  51. package/dist/prompt.d.ts.map +1 -0
  52. package/dist/prompt.js +70 -0
  53. package/dist/prompt.js.map +1 -0
  54. package/dist/types.d.ts +153 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +2 -0
  57. package/dist/types.js.map +1 -0
  58. package/docs/ARCHITECTURE.md +25 -0
  59. package/docs/MIGRATION.md +28 -0
  60. package/docs/PUBLISHING.md +128 -0
  61. package/docs/SUPPORT.md +17 -0
  62. package/install.mjs +6 -0
  63. package/package.json +73 -0
  64. package/schema/release.config.schema.json +209 -0
  65. package/template/android/keystore.properties.example +7 -0
  66. package/template/android/proguard-rules.rn-local-release.pro +28 -0
  67. package/template/docs/LOCAL_RELEASE.md +85 -0
  68. package/template/fastlane/.env.example +20 -0
  69. package/template/fastlane/Appfile +10 -0
  70. package/template/fastlane/Fastfile +203 -0
  71. package/template/fastlane/lib/rn_local_release.rb +700 -0
  72. package/template/ios/exportOptions.plist +18 -0
  73. package/template/scripts/print-android-signing-fingerprints.sh +62 -0
  74. package/template/secrets/.gitignore +3 -0
  75. package/template/secrets/README.md +12 -0
@@ -0,0 +1,28 @@
1
+ # Base React Native R8 keep rules (conservative).
2
+ # Do not replace project-specific SDK keeps; append project rules after this file.
3
+
4
+ -keepattributes Signature
5
+ -keepattributes *Annotation*
6
+ -keepattributes InnerClasses
7
+ -keepattributes EnclosingMethod
8
+ -keepattributes SourceFile,LineNumberTable
9
+ -keepattributes Exceptions
10
+
11
+ -keep class com.facebook.react.** { *; }
12
+ -keep class com.facebook.hermes.** { *; }
13
+ -keep class com.facebook.jni.** { *; }
14
+ -keep class com.facebook.soloader.** { *; }
15
+ -keep class com.facebook.yoga.** { *; }
16
+ -keep class * extends com.facebook.react.bridge.NativeModule { *; }
17
+ -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
18
+ -keepclassmembers class * {
19
+ @com.facebook.react.uimanager.annotations.ReactProp <methods>;
20
+ }
21
+ -keepclassmembers class * {
22
+ @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>;
23
+ }
24
+
25
+ -keep class com.facebook.react.turbomodule.** { *; }
26
+ -keep class com.facebook.react.fabric.** { *; }
27
+
28
+ -dontwarn com.facebook.**
@@ -0,0 +1,85 @@
1
+ # Local Fastlane release (laptop CI/CD)
2
+
3
+ This project uses **[@ahmedsamirelsaka/react-native-local-release](https://www.npmjs.com/package/@ahmedsamirelsaka/react-native-local-release)** v2:
4
+ a security-first local Fastlane kit for bare React Native iOS + Android.
5
+
6
+ ## Split of concerns
7
+
8
+ | Kind | Where | Examples |
9
+ |------|-------|----------|
10
+ | Tracked metadata | `fastlane/release.config.json` | package name, team ID, scheme, tracks, version sources, logging, archives |
11
+ | Managed install state | `.rn-local-release/manifest.json` | hashes of managed files (non-secret) |
12
+ | Local credentials | Keychain/vault (default macOS) or `fastlane/.env` + `secrets/` | ASC `.p8`, Play JSON, keystore passwords |
13
+ | Crash logs | `logs/` (gitignored, redacted) | installer / Fastlane failures |
14
+ | Optional upload archive | `versions/` (gitignored, opt-in) | copies of uploaded IPA/AAB |
15
+
16
+ Never paste private keys, passwords, or JSON credentials into Git, chat, docs, or screenshots.
17
+
18
+ How to create credentials: see [RELEASE_CREDENTIALS.md](./RELEASE_CREDENTIALS.md).
19
+
20
+ ## Install / reinstall
21
+
22
+ Prefer an **exact npm version** (do not run floating `github:` HEAD in daily workflows):
23
+
24
+ ```bash
25
+ npx @ahmedsamirelsaka/react-native-local-release@2.0.0 install --project .
26
+ ```
27
+
28
+ Useful flags:
29
+
30
+ ```bash
31
+ --dry-run
32
+ --team-id YOURTEAMID
33
+ --package-name com.example.app
34
+ --ios-scheme YourScheme
35
+ --fixed-ios-build 1
36
+ --store-uploaded-versions / --no-store-uploaded-versions
37
+ --setup-credentials / --skip-credentials
38
+ --credentials-only
39
+ --non-interactive
40
+ ```
41
+
42
+ Interactive install asks:
43
+
44
+ 1. Configure Apple / Play / keystore now?
45
+ 2. Store uploaded IPA/AAB copies under `versions/`?
46
+
47
+ Reinstall merges existing `release.config.json` instead of wiping custom tracks/gates.
48
+
49
+ ## Prerequisites
50
+
51
+ - macOS with Xcode (iOS)
52
+ - Android SDK / JDK for Gradle
53
+ - Node 18+, Yarn/npm/pnpm
54
+ - Ruby compatible with Fastlane (`bundle install`)
55
+ - ASC API key + Play service account + upload keystore
56
+
57
+ ## Daily commands
58
+
59
+ ```bash
60
+ bundle install
61
+ yarn release:doctor
62
+ yarn release:credentials
63
+ yarn release:compile # typecheck + IPA + AAB (no bump, no upload)
64
+ yarn release:upload # upload last compile
65
+ yarn release:beta # bump + compile + upload
66
+ ```
67
+
68
+ Promote to production requires confirmation:
69
+
70
+ ```bash
71
+ RN_LOCAL_RELEASE_YES=1 yarn release:ios:promote version:x.y.z build:n
72
+ RN_LOCAL_RELEASE_YES=1 yarn release:android:promote version_code:n
73
+ ```
74
+
75
+ ## Uninstall
76
+
77
+ ```bash
78
+ npx @ahmedsamirelsaka/react-native-local-release@2.0.0 uninstall --project . --yes
79
+ ```
80
+
81
+ ## Troubleshooting
82
+
83
+ - Check redacted files under `logs/`
84
+ - Run `rn-local-release audit --project .` if credentials look tracked
85
+ - Partial dual-upload failures leave `build/upload-journal.json` describing which store succeeded
@@ -0,0 +1,20 @@
1
+ # Local Fastlane credentials — copy to fastlane/.env and fill in.
2
+ # Never commit real values. Paths may be absolute or relative to the repo root.
3
+
4
+ # --- Apple App Store Connect API key ---
5
+ # Create at: App Store Connect → Users and Access → Integrations → App Store Connect API
6
+ ASC_KEY_ID=
7
+ ASC_ISSUER_ID=
8
+ ASC_KEY_FILEPATH=secrets/AuthKey_XXXXXXXXXX.p8
9
+ # Optional Apple ID email (only needed for interactive Apple ID auth fallback)
10
+ # APPLE_ID=you@example.com
11
+
12
+ # --- Google Play service account ---
13
+ # JSON key downloaded after creating a Play Console service account
14
+ PLAY_JSON_KEY_PATH=secrets/play-store-service-account.json
15
+
16
+ # --- Android upload keystore ---
17
+ MYAPP_UPLOAD_STORE_FILE=keystore.jks
18
+ MYAPP_UPLOAD_KEY_ALIAS=key0
19
+ MYAPP_UPLOAD_STORE_PASSWORD=
20
+ MYAPP_UPLOAD_KEY_PASSWORD=
@@ -0,0 +1,10 @@
1
+ # Generated by react-native-local-release. Non-secret identifiers only.
2
+ # Credential paths come from environment / fastlane/.env — never hardcode secrets.
3
+
4
+ app_identifier("{{bundleIdentifier}}")
5
+ package_name("{{packageName}}")
6
+ team_id("{{teamId}}")
7
+
8
+ apple_id(ENV["APPLE_ID"]) if ENV["APPLE_ID"] && !ENV["APPLE_ID"].empty?
9
+
10
+ json_key_file(ENV["PLAY_JSON_KEY_PATH"]) if ENV["PLAY_JSON_KEY_PATH"] && !ENV["PLAY_JSON_KEY_PATH"].empty?
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ opt_out_usage
4
+ default_platform(:ios)
5
+
6
+ import("./lib/rn_local_release.rb")
7
+
8
+ desc "Validate config paths and print current versions (no secrets required)"
9
+ lane :doctor do
10
+ doctor!
11
+ end
12
+
13
+ desc "Validate Apple and Google upload credentials"
14
+ lane :credentials do
15
+ load_asc_api_key
16
+ UI.success("App Store Connect API key loaded successfully.")
17
+ validate_play_store_json_key(json_key: play_json_key_path)
18
+ UI.success("Play Store JSON key validated successfully.")
19
+ end
20
+
21
+ desc "Run shared JS verification"
22
+ lane :verify do
23
+ run_verify!
24
+ end
25
+
26
+ desc "Bump / set marketing version + Android versionCode (and iOS build per strategy)"
27
+ lane :bump_version do |options|
28
+ bumped = bump_versions!(options)
29
+ UI.message(
30
+ "Next store upload will use #{bumped[:version]} " \
31
+ "(Android #{bumped[:android_build]}, iOS #{bumped[:ios_build]})"
32
+ )
33
+ end
34
+
35
+ desc "Alias of bump_version for prepare-before-build workflows"
36
+ lane :prepare do |options|
37
+ bumped = bump_versions!(options)
38
+ UI.message(
39
+ "Prepared #{bumped[:version]} " \
40
+ "(Android #{bumped[:android_build]}, iOS #{bumped[:ios_build]})"
41
+ )
42
+ end
43
+
44
+ desc "Typecheck and compile iOS IPA + Android AAB without uploading"
45
+ lane :compile do
46
+ compile_all!
47
+ end
48
+
49
+ desc "Build iOS IPA and Android AAB without uploading"
50
+ lane :build_all do
51
+ compile_all!
52
+ end
53
+
54
+ desc "Upload previously compiled IPA + AAB using release-manifest.json"
55
+ lane :upload_all do |options|
56
+ upload_all_resumable!(options)
57
+ end
58
+
59
+ desc "Bump (unless skipped), compile both platforms, then upload TestFlight + Play beta track"
60
+ lane :beta_all do |options|
61
+ unless skip_flag?(options, :skip_bump)
62
+ bumped = bump_versions!(options)
63
+ UI.important(
64
+ "Version is now #{bumped[:version]} " \
65
+ "(Android #{bumped[:android_build]}, iOS #{bumped[:ios_build]}). Compiling, then uploading."
66
+ )
67
+ else
68
+ UI.important(
69
+ "Using current version #{current_marketing_version} " \
70
+ "(Android #{current_android_build}, iOS #{current_ios_build}). " \
71
+ "Compiling, then uploading."
72
+ )
73
+ end
74
+
75
+ compile_all!
76
+ upload_all_resumable!(options)
77
+ end
78
+
79
+ platform :ios do
80
+ desc "Validate App Store Connect API credentials"
81
+ lane :credentials do
82
+ load_asc_api_key
83
+ UI.success("App Store Connect API key loaded successfully.")
84
+ end
85
+
86
+ desc "Run lint, TypeScript, and tests"
87
+ lane :verify do
88
+ run_verify!
89
+ end
90
+
91
+ desc "Build a signed App Store IPA (no upload)"
92
+ lane :build do
93
+ compile_js!
94
+ build_ios_ipa!
95
+ write_platform_manifest!(:ios)
96
+ end
97
+
98
+ desc "Compile IPA then upload to TestFlight"
99
+ lane :beta do |options|
100
+ bump_versions!(options) unless skip_flag?(options, :skip_bump)
101
+ compile_js!
102
+ build_ios_ipa!
103
+ write_platform_manifest!(:ios)
104
+ assert_manifest_artifacts!(:ios)
105
+ upload_ios!(options)
106
+ end
107
+
108
+ desc "Upload an already-compiled IPA from the release manifest"
109
+ lane :upload do |options|
110
+ assert_manifest_artifacts!(:ios)
111
+ upload_ios!(options)
112
+ end
113
+
114
+ desc "Submit an already-uploaded build for App Store review"
115
+ lane :promote do |options|
116
+ ensure_clean_git!
117
+ load_asc_api_key
118
+ app_version = require_option!(options, :version)
119
+ build_number = require_option!(options, :build)
120
+ confirm_promote!(:ios, {
121
+ "app" => config.dig("app", "bundleIdentifier"),
122
+ "version" => app_version,
123
+ "build" => build_number,
124
+ "action" => "submit_for_review"
125
+ })
126
+ UI.user_error!("Set RN_LOCAL_RELEASE_YES=1 to confirm production promote") unless ENV["RN_LOCAL_RELEASE_YES"] == "1" || ENV["CI"] == "true"
127
+
128
+ upload_to_app_store(
129
+ app_version: app_version,
130
+ build_number: build_number.to_s,
131
+ submit_for_review: true,
132
+ automatic_release: false,
133
+ force: true,
134
+ skip_binary_upload: true,
135
+ skip_metadata: true,
136
+ skip_screenshots: true,
137
+ precheck_include_in_app_purchases: false
138
+ )
139
+ end
140
+ end
141
+
142
+ platform :android do
143
+ desc "Validate Google Play service-account credentials"
144
+ lane :credentials do
145
+ validate_play_store_json_key(json_key: play_json_key_path)
146
+ UI.success("Play Store JSON key validated successfully.")
147
+ end
148
+
149
+ desc "Run lint, TypeScript, and tests"
150
+ lane :verify do
151
+ run_verify!
152
+ end
153
+
154
+ desc "Build a signed Play App Bundle (no upload)"
155
+ lane :build do
156
+ compile_js!
157
+ build_android_aab!
158
+ write_platform_manifest!(:android)
159
+ end
160
+
161
+ desc "Compile AAB then upload to the configured Play beta track"
162
+ lane :beta do |options|
163
+ bump_versions!(options) unless skip_flag?(options, :skip_bump)
164
+ compile_js!
165
+ build_android_aab!
166
+ write_platform_manifest!(:android)
167
+ assert_manifest_artifacts!(:android)
168
+ upload_android!
169
+ end
170
+
171
+ desc "Upload an already-compiled AAB from the release manifest"
172
+ lane :upload do
173
+ assert_manifest_artifacts!(:android)
174
+ upload_android!
175
+ end
176
+
177
+ desc "Promote a specific versionCode from beta track to production"
178
+ lane :promote do |options|
179
+ ensure_clean_git!
180
+ version_code = require_option!(options, :version_code)
181
+ confirm_promote!(:android, {
182
+ "package" => config.dig("app", "packageName"),
183
+ "versionCode" => version_code,
184
+ "fromTrack" => config.dig("android", "playTrackBeta"),
185
+ "toTrack" => config.dig("android", "playTrackPromote")
186
+ })
187
+ UI.user_error!("Set RN_LOCAL_RELEASE_YES=1 to confirm production promote") unless ENV["RN_LOCAL_RELEASE_YES"] == "1" || ENV["CI"] == "true"
188
+
189
+ upload_to_play_store(
190
+ package_name: config.dig("app", "packageName"),
191
+ track: config.dig("android", "playTrackBeta"),
192
+ track_promote_to: config.dig("android", "playTrackPromote"),
193
+ version_code: version_code.to_i,
194
+ json_key: play_json_key_path,
195
+ skip_upload_apk: true,
196
+ skip_upload_aab: true,
197
+ skip_upload_metadata: true,
198
+ skip_upload_images: true,
199
+ skip_upload_screenshots: true,
200
+ skip_upload_changelogs: true
201
+ )
202
+ end
203
+ end