expo-release-it 0.3.2 → 0.5.0
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.
- package/README.md +5 -298
- package/build/command/build.js +90 -43
- package/build/command/build.js.map +1 -1
- package/build/command/bump.js +219 -24
- package/build/command/bump.js.map +1 -1
- package/build/command/init.js +84 -22
- package/build/command/init.js.map +1 -1
- package/build/command/pull.js +84 -37
- package/build/command/pull.js.map +1 -1
- package/build/command/submit.js +90 -43
- package/build/command/submit.js.map +1 -1
- package/build/command/upload.js +90 -43
- package/build/command/upload.js.map +1 -1
- package/build/index.js +196 -47
- package/build/index.js.map +1 -1
- package/build/type/ExpoReleaseItConfiguration.d.d.ts +54 -0
- package/build/type/ExpoReleaseItConfiguration.d.js +1 -0
- package/build/type/ExpoReleaseItConfiguration.d.js.map +1 -0
- package/build/util/EnvUtil.d.ts +2 -1
- package/build/util/EnvUtil.js +2 -0
- package/build/util/EnvUtil.js.map +1 -1
- package/build/util/FastlaneOption.js +20 -19
- package/build/util/FastlaneOption.js.map +1 -1
- package/build/util/MetadataSyncUtil.js +20 -19
- package/build/util/MetadataSyncUtil.js.map +1 -1
- package/build/util/OptionHolder.d.ts +9 -1
- package/build/util/OptionHolder.js +20 -19
- package/build/util/OptionHolder.js.map +1 -1
- package/build/util/generateAppStoreConnectApiKeyFile.js +20 -19
- package/build/util/generateAppStoreConnectApiKeyFile.js.map +1 -1
- package/build/util/injectTemplatePlaceHolders.js +20 -19
- package/build/util/injectTemplatePlaceHolders.js.map +1 -1
- package/build/util/input/InqueryInputs.d.ts +0 -1
- package/build/util/input/InqueryInputs.js +20 -34
- package/build/util/input/InqueryInputs.js.map +1 -1
- package/build/util/parseConfigFile.d.ts +3 -0
- package/build/util/parseConfigFile.js +151 -0
- package/build/util/parseConfigFile.js.map +1 -0
- package/build/util/setup/VersionUtil.d.ts +3 -1
- package/build/util/setup/VersionUtil.js +45 -19
- package/build/util/setup/VersionUtil.js.map +1 -1
- package/build/util/setup/hydrateKeyholderFileValues.js +20 -19
- package/build/util/setup/hydrateKeyholderFileValues.js.map +1 -1
- package/build/util/setup/prepareAndroid.js +20 -19
- package/build/util/setup/prepareAndroid.js.map +1 -1
- package/build/util/setup/prepareIos.js +20 -19
- package/build/util/setup/prepareIos.js.map +1 -1
- package/build/util/setup/setup.js +85 -22
- package/build/util/setup/setup.js.map +1 -1
- package/build/util/throwError.js +8 -0
- package/build/util/throwError.js.map +1 -1
- package/expo-release-it.schema.json +77 -0
- package/package.json +17 -18
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
Opinionated Expo CICD workflow CLI for building & uploading & submitting Expo projects on your machine
|
|
6
6
|
|
|
7
|
+
# Documentation
|
|
8
|
+
|
|
9
|
+
Visit our [Documentation Site](https://expo-release-it.mjstudio.net)
|
|
10
|
+
|
|
7
11
|
# Features
|
|
8
12
|
|
|
9
13
|
- 🎉 No **EAS**
|
|
@@ -12,304 +16,7 @@ Opinionated Expo CICD workflow CLI for building & uploading & submitting Expo pr
|
|
|
12
16
|
- 🌍 Works with [Expo CNG](https://docs.expo.dev/workflow/continuous-native-generation/) mode (also available in non-CNG environments)
|
|
13
17
|
- 📦 Build artifacts **locally** (`apk`, `aab`, `ipa`)
|
|
14
18
|
- 🚀 Upload artifacts to Google Play Console Internal Testing Track and iOS TestFlight
|
|
15
|
-
- ✅ Submit releases for review
|
|
16
|
-
|
|
17
|
-
# Why?
|
|
18
|
-
|
|
19
|
-
**You don't need Expo EAS and to understand how it works in most small projects and our machine is much faster than using the cloud.**
|
|
20
|
-
|
|
21
|
-
<details>
|
|
22
|
-
<summary>Full Details</summary>
|
|
23
|
-
|
|
24
|
-
Expo EAS is convenient, but it requires additional configuration files, console setup, and a conceptual understanding of Over-The-Air (OTA) updates. Also, builds must be performed on EAS Cloud, which is not free and can be slow.
|
|
25
|
-
|
|
26
|
-
While EAS is useful for larger teams, if you are developing alone or with just a few people and question the need for such a process, `expo-release-it` is the answer.
|
|
27
|
-
|
|
28
|
-
Based on years of experience developing with React Native, I encourage a more traditional approach: build APK, AAB, and IPA files locally, upload them to each platform’s store testing track, and request reviews—without worrying about binary versions, OTA update versions, or branch management.
|
|
29
|
-
|
|
30
|
-
This approach is much faster, simpler, and, most importantly, allows you to take full advantage of your computer’s fast CPU.
|
|
31
|
-
|
|
32
|
-
OTA updates are a powerful tool in React Native, but to fully take advantage of them, you need a self-hosted CDN server, a version management console both in the cloud and inside the app, and you have to separately manage binary versions and bundle versions—all of which introduce significant complexity and semantic overhead that often outweigh the benefits of implementing OTA updates. Furthermore, due to a general lack of deep understanding about OTA updates, issues like native library version mismatches can occur frequently, so OTA updates are excluded by default.
|
|
33
|
-
|
|
34
|
-
I’m also a big fan of OTA updates, and I’ve enjoyed a lot of efficiency when working in larger teams, but it always required setting up many supporting systems in advance.
|
|
35
|
-
|
|
36
|
-
`expo-release-it` is a CLI tool that encapsulates the know-how I have gained over years of automating build and review processes.
|
|
37
|
-
Internally, it ports and integrates tools like Fastlane and Match to automate native binary builds and review requests.
|
|
38
|
-
|
|
39
|
-
Therefore, this tool enforces an opinionated versioning, build, and review request workflow.
|
|
40
|
-
However, once you understand this approach, your app deployment process will become significantly faster.
|
|
41
|
-
|
|
42
|
-
</details>
|
|
43
|
-
|
|
44
|
-
# Structurual Requirements
|
|
45
|
-
|
|
46
|
-
- `Version Code(Android)` and `Builder Number(iOS)` are the same.
|
|
47
|
-
- All Keys, Credentials(except iOS certificates & provisioning profiles served in Github separately) are stored in VCS
|
|
48
|
-
|
|
49
|
-
# Getting Started
|
|
50
|
-
|
|
51
|
-
## 1. Ruby, Bundler
|
|
52
|
-
|
|
53
|
-
`expo-release-it` requires `bundler` of ruby is available in your environment to run `Fastlane` internally.
|
|
54
|
-
|
|
55
|
-
If not, set up your environment so that `ruby` and `bundler` are available by following [Ruby Install Guide](https://www.ruby-lang.org/en/downloads/)
|
|
56
|
-
|
|
57
|
-
## 2. Prepare Keys & Credentials
|
|
58
|
-
|
|
59
|
-
`init` command generates sample key files structure in `expo-release-it/key`. They are **noob files** and you must replace file contents.
|
|
60
|
-
|
|
61
|
-
> [!IMPORTANT]
|
|
62
|
-
**You must prepare all required key files in `expo-release-it/key` exactly the same filenames.**
|
|
63
|
-
|
|
64
|
-
### `android_play_console_service_account.json`
|
|
65
|
-
|
|
66
|
-
Google Play Console actions require authentication using Google Service Account.
|
|
67
|
-
|
|
68
|
-
You can issue new Google Play Service Account by following Guide
|
|
69
|
-
and prepare `json` file.
|
|
70
|
-
|
|
71
|
-
- [Fastlane Supply JSON Key Setup Guide](https://docs.fastlane.tools/actions/supply/#setup)
|
|
72
|
-
- [How to Get Your Google Play JSON Key](https://help.radio.co/en/articles/6232140-how-to-get-your-google-play-json-key)
|
|
73
|
-
|
|
74
|
-
### `android_release.keystore`
|
|
75
|
-
|
|
76
|
-
Prepare your android release keystore file for **uploading** and **signing** Android build artifacts.
|
|
77
|
-
|
|
78
|
-
Additional passwords, alias will be prompted during the `init` command and be stored in `keyholder.json`.
|
|
79
|
-
|
|
80
|
-
- [Keystore generation with Android Studio](https://developer.android.com/studio/publish/app-signing.html#generate-key)
|
|
81
|
-
- [Keystore generation with CLI](https://gist.github.com/henriquemenezes/70feb8fff20a19a65346e48786bedb8f)
|
|
82
|
-
|
|
83
|
-
### `ios_app_store_connect_api_key`
|
|
84
|
-
|
|
85
|
-
App Store Connect actions require authentication using App Store Connect Api Key(.p8)
|
|
86
|
-
|
|
87
|
-
Additional `issuer_id`, `key_id` values will be prompted during the `init` command and be stored in `keyholder.json`
|
|
88
|
-
|
|
89
|
-
- [Guide](https://www.revenuecat.com/docs/service-credentials/itunesconnect-app-specific-shared-secret/app-store-connect-api-key-configuration)
|
|
90
|
-
- [Apple Docs Guide](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api)
|
|
91
|
-
|
|
92
|
-
## 3. Create & Configure app on the stores as much as possible
|
|
93
|
-
|
|
94
|
-
Create and configure your application in Google Play Console & App Store Connect as many as possible.
|
|
95
|
-
|
|
96
|
-
You'd have to fill your key & credentials information using `init` command and pull store metadatas using `pull` command later.
|
|
97
|
-
|
|
98
|
-
You would need to upload & publish your first artifact, release manually at first.
|
|
99
|
-
|
|
100
|
-
## 4. Set binary version in expo config file.
|
|
101
|
-
|
|
102
|
-
The following buildNumber, versionCode format `ABBBCCC` is not mandatory but recommended for readability.
|
|
103
|
-
|
|
104
|
-
If your expo config file is `app.json`, then set like the following.
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"expo": {
|
|
109
|
-
"version": "1.2.3",
|
|
110
|
-
"ios": {
|
|
111
|
-
"buildNumber": "1002003"
|
|
112
|
-
},
|
|
113
|
-
"android": {
|
|
114
|
-
"versionCode": 1002003
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
If your expo config file is `app.config.(js|ts|mjs|cjs)`, then set like the following.
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import type { ExpoConfig, ConfigContext } from 'expo/config';
|
|
125
|
-
const VERSION_NAME = '1.2.3'; // VERSION_NAME variable is required.
|
|
126
|
-
const VERSION_CODE = 1002003; // VERSION_CODE variable is required.
|
|
127
|
-
|
|
128
|
-
export default ({ config }: ConfigContext): ExpoConfig => {
|
|
129
|
-
return {
|
|
130
|
-
...config,
|
|
131
|
-
version: VERSION_NAME,
|
|
132
|
-
ios: {
|
|
133
|
-
buildNumber: VERSION_CODE + '',
|
|
134
|
-
},
|
|
135
|
-
android: {
|
|
136
|
-
versionCode: VERSION_CODE,
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## 5. Update `.gitignore`
|
|
144
|
-
|
|
145
|
-
```gitignore
|
|
146
|
-
# Expo Release It
|
|
147
|
-
|
|
148
|
-
expo-release-it/.temp
|
|
149
|
-
android/vendor/bundle
|
|
150
|
-
ios/vendor/bundle
|
|
151
|
-
!*.jks
|
|
152
|
-
!*.p8
|
|
153
|
-
!*.keystore
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## 6. Run `expo-release-it init`
|
|
157
|
-
|
|
158
|
-
# Usage
|
|
159
|
-
|
|
160
|
-
```shell
|
|
161
|
-
npx expo-release-it (init|bump|pull|build|upload|submit) [options]
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
All commands are powered by [Commander.js](https://github.com/tj/commander.js?) means you can query all available options with `--help` or `-h`.
|
|
165
|
-
|
|
166
|
-
## init
|
|
167
|
-
|
|
168
|
-
**Configure resources and environment**
|
|
169
|
-
|
|
170
|
-
```shell
|
|
171
|
-
npx expo-release-it init
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
The `init` command asks you for many form fields, and the information is saved in `expo-release-it/keyholder.json` in your project.
|
|
175
|
-
|
|
176
|
-
Even after running `init`, you can manually edit `keyholder.json`, and all subsequent commands will use the updated values.
|
|
177
|
-
|
|
178
|
-
The resources & output directory structure is the following.
|
|
179
|
-
|
|
180
|
-
```text
|
|
181
|
-
📁 expo-release-it/
|
|
182
|
-
├── 📁 key/ # key & certificate files
|
|
183
|
-
├── 📁 metadata/ # result of `pull`
|
|
184
|
-
│ ├── 📁 android/ # android store metadatas
|
|
185
|
-
│ └── 📁 ios/ # ios store metadatas
|
|
186
|
-
├── 📁 output/ # result of `build`
|
|
187
|
-
│ ├── 📁 android/ # android build output
|
|
188
|
-
│ └── 📁 ios/ # ios build output
|
|
189
|
-
└── keyholder.json
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## bump
|
|
193
|
-
|
|
194
|
-
**Bump binary release patch version with modifying expo config file**
|
|
195
|
-
|
|
196
|
-
```shell
|
|
197
|
-
npx expo-release-it bump
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## pull
|
|
201
|
-
|
|
202
|
-
**Download metadatas from stores**
|
|
203
|
-
|
|
204
|
-
```shell
|
|
205
|
-
npx expo-release-it pull
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
The downloaded metadatas are stored in `expo-release-it/metadata`.
|
|
209
|
-
|
|
210
|
-
Check the following out to configure metadatas.
|
|
211
|
-
|
|
212
|
-
- [Android Metadata Manage Guide](https://docs.fastlane.tools/actions/supply/#images-and-screenshots)
|
|
213
|
-
- [iOS Metadata Manage Guide](https://docs.fastlane.tools/actions/deliver/#available-language-codes)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
## build
|
|
217
|
-
|
|
218
|
-
**Build artifacts (apk, aab, ipa)**
|
|
219
|
-
|
|
220
|
-
```shell
|
|
221
|
-
npx expo-release-it build
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## upload
|
|
225
|
-
|
|
226
|
-
**Upload artifact to play console internal test track(android) and testflight(ios)**
|
|
227
|
-
|
|
228
|
-
```shell
|
|
229
|
-
npx expo-release-it upload
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## submit
|
|
233
|
-
|
|
234
|
-
**Submit Google Play Console & App Store Connect Review with latest testing track**
|
|
235
|
-
|
|
236
|
-
```shell
|
|
237
|
-
npx expo-release-it submit
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
# About Security
|
|
241
|
-
|
|
242
|
-
That’s right. You might be wondering whether storing files like .p8, keystore files, or key values in version control is truly secure.
|
|
243
|
-
In conclusion, if you’re using a private repository, you can consider it to be somewhat safe.
|
|
244
|
-
|
|
245
|
-
For example, Fastlane Match also uses OpenSSL encryption, but it still stores certificates and profiles in a private Git repository.
|
|
246
|
-
|
|
247
|
-
While you could implement additional security policies, I haven’t taken any extra measures for now.
|
|
248
|
-
If you need further encryption, you can build middleware in your pipeline that runs expo-release-it so that everything in the expo-release-it directory goes through encryption and decryption processes.
|
|
249
|
-
|
|
250
|
-
Any suggestions are welcome.
|
|
251
|
-
|
|
252
|
-
# Troubleshooting
|
|
253
|
-
|
|
254
|
-
## [iOS - submit] Add information to the :submission_information option...
|
|
255
|
-
|
|
256
|
-
Add [Complying with Encryption Export Regulartions options](https://developer.apple.com/documentation/security/complying-with-encryption-export-regulations?language=objc) to your expo config file.
|
|
257
|
-
|
|
258
|
-
Example `app.json`
|
|
259
|
-
|
|
260
|
-
```json
|
|
261
|
-
{
|
|
262
|
-
"expo": {
|
|
263
|
-
"ios": {
|
|
264
|
-
"config": {
|
|
265
|
-
"usesNonExemptEncryption": false
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## [iOS] failed to load command: fastlane
|
|
273
|
-
|
|
274
|
-
This means lane of fastlane has been failed. You must check stdout of fastlane action in console.
|
|
275
|
-
|
|
276
|
-
### invalid curve name
|
|
277
|
-
|
|
278
|
-
check out if contents of `ios_app_store_connect_api_key.p8` are valid.
|
|
279
|
-
|
|
280
|
-
## [iOS - submit] The provided entity is missing a required attribute - ...
|
|
281
|
-
|
|
282
|
-
You have to fill required metadata attributes of iOS in `expo-release-it/metadata/ios`.
|
|
283
|
-
|
|
284
|
-
You also skip uploading metadatas with opt out the metadata uploading from the cli prompt.
|
|
285
|
-
|
|
286
|
-
## [iOS - submit] This resource cannot be reviewed
|
|
287
|
-
|
|
288
|
-
You have to fill all necessary metadata to submit app for the reivew.
|
|
289
|
-
|
|
290
|
-
Check yourself if app can be submitted manually at the app store connect yourself first.
|
|
291
|
-
|
|
292
|
-
## [iOS] Provisioning profile "..." doesn't include signing certificate "..."
|
|
293
|
-
|
|
294
|
-
You might need to revoke iOS Certificates & Provisioning Profile and generate again.
|
|
295
|
-
|
|
296
|
-
```shell
|
|
297
|
-
cd ios
|
|
298
|
-
bundle
|
|
299
|
-
bundle exec fastlane match nuke distribution # revoke all certificates
|
|
300
|
-
|
|
301
|
-
cd ..
|
|
302
|
-
npx expo-release-it built -p ios # command you tried, this generate required certificates automatically
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
## [Android] Google Api Error: Invalid request - Package not found: ...
|
|
306
|
-
|
|
307
|
-
At first, you have to upload your artifacts manually.
|
|
308
|
-
First, create an internal testing track and then upload your artifacts (AAB or APK files).
|
|
309
|
-
|
|
310
|
-
## [Android] Google Api Error: Invalid request - Only releases with status draft may be created on draft app.
|
|
311
|
-
|
|
312
|
-
If you have just created your app and have never released it to production before, please fill out all the required metadata manually, publish the app manually for the first time, and then try again.
|
|
19
|
+
- ✅ Submit releases for store review
|
|
313
20
|
|
|
314
21
|
# Licenses
|
|
315
22
|
|
package/build/command/build.js
CHANGED
|
@@ -58,17 +58,16 @@ var package_default = {
|
|
|
58
58
|
name: "expo-release-it",
|
|
59
59
|
module: "src/index.ts",
|
|
60
60
|
type: "module",
|
|
61
|
-
version: "0.
|
|
61
|
+
version: "0.4.0",
|
|
62
62
|
license: "MIT",
|
|
63
|
-
homepage: "https://
|
|
63
|
+
homepage: "https://expo-release-it.mjstudio.net/",
|
|
64
64
|
repository: "https://github.com/mym0404/expo-release-it",
|
|
65
65
|
scripts: {
|
|
66
|
-
build: "tsup",
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
t: "tsc --noEmit -p ."
|
|
66
|
+
build: "pnpm build:json-schema-type && tsup",
|
|
67
|
+
"build:json-schema-type": "json2ts --input expo-release-it.schema.json --output src/type/ExpoReleaseItConfiguration.d.ts",
|
|
68
|
+
dev: "pnpm build && NODE_ENV=development node bin/expo-release-it.mjs",
|
|
69
|
+
release: "pnpm build && pnpm run t && release-it",
|
|
70
|
+
t: "lefthook run check"
|
|
72
71
|
},
|
|
73
72
|
dependencies: {
|
|
74
73
|
"@inquirer/prompts": "^7.4.1",
|
|
@@ -78,8 +77,8 @@ var package_default = {
|
|
|
78
77
|
execa: "^9.5.2",
|
|
79
78
|
"fs-extra": "^11.3.0",
|
|
80
79
|
ora: "^8.2.0",
|
|
81
|
-
react: "
|
|
82
|
-
"react-native": "
|
|
80
|
+
react: "catalog:native",
|
|
81
|
+
"react-native": "catalog:native",
|
|
83
82
|
semver: "^7.7.1",
|
|
84
83
|
url: "^0.11.4"
|
|
85
84
|
},
|
|
@@ -88,29 +87,29 @@ var package_default = {
|
|
|
88
87
|
"@release-it/conventional-changelog": "^10.0.1",
|
|
89
88
|
"@types/fs-extra": "^11.0.4",
|
|
90
89
|
"@types/semver": "^7.7.0",
|
|
90
|
+
"json-schema-to-typescript": "^15.0.4",
|
|
91
91
|
lefthook: "^1.11.11",
|
|
92
|
-
prettier: "
|
|
92
|
+
prettier: "catalog:",
|
|
93
93
|
"release-it": "^19.0.1",
|
|
94
94
|
"tiny-glob": "^0.2.9",
|
|
95
95
|
tsup: "^8.4.0",
|
|
96
|
-
typescript: "
|
|
96
|
+
typescript: "catalog:",
|
|
97
|
+
vitest: "^3.1.2"
|
|
97
98
|
},
|
|
98
|
-
workspaces: [
|
|
99
|
-
"example"
|
|
100
|
-
],
|
|
101
99
|
bin: "./bin/expo-release-it.mjs",
|
|
102
100
|
files: [
|
|
103
101
|
"build",
|
|
104
102
|
"package.json",
|
|
105
103
|
"bin",
|
|
106
|
-
"template"
|
|
104
|
+
"template",
|
|
105
|
+
"expo-release-it.schema.json"
|
|
107
106
|
],
|
|
108
|
-
packageManager: "yarn@4.9.1",
|
|
109
107
|
commitlint: {
|
|
110
108
|
extends: [
|
|
111
109
|
"@commitlint/config-conventional"
|
|
112
110
|
]
|
|
113
|
-
}
|
|
111
|
+
},
|
|
112
|
+
packageManager: "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
|
|
114
113
|
};
|
|
115
114
|
|
|
116
115
|
// src/util/OptionHolder.ts
|
|
@@ -121,7 +120,9 @@ var OptionHolder = {
|
|
|
121
120
|
rootDir: resolve2(fileURLToPath(import.meta.url), "../.."),
|
|
122
121
|
templateDir: resolve2(fileURLToPath(import.meta.url), "../../template")
|
|
123
122
|
},
|
|
124
|
-
input: {
|
|
123
|
+
input: {
|
|
124
|
+
git: {}
|
|
125
|
+
},
|
|
125
126
|
keyholderMap: {},
|
|
126
127
|
templateDirNames: ["key"],
|
|
127
128
|
projectDir: "",
|
|
@@ -319,6 +320,11 @@ async function hydrateKeyholderFileValues() {
|
|
|
319
320
|
}
|
|
320
321
|
}
|
|
321
322
|
|
|
323
|
+
// src/util/EnvUtil.ts
|
|
324
|
+
var isDev = process.env.NODE_ENV === "development";
|
|
325
|
+
var isWin = process.platform.startsWith("win");
|
|
326
|
+
var isTest = process.env.NODE_ENV === "test";
|
|
327
|
+
|
|
322
328
|
// src/util/throwError.ts
|
|
323
329
|
function throwError(message, e) {
|
|
324
330
|
if (e) {
|
|
@@ -326,11 +332,15 @@ function throwError(message, e) {
|
|
|
326
332
|
} else {
|
|
327
333
|
logger.error(message);
|
|
328
334
|
}
|
|
335
|
+
if (isTest) {
|
|
336
|
+
throw new Error("throwError");
|
|
337
|
+
}
|
|
329
338
|
process.exit(1);
|
|
330
339
|
}
|
|
331
340
|
|
|
332
341
|
// src/util/setup/VersionUtil.ts
|
|
333
342
|
import semver from "semver";
|
|
343
|
+
import { padZero } from "@mj-studio/js-util";
|
|
334
344
|
var versionNameRegex = () => /const\s+VERSION_NAME\s*?=\s*?['"]([\d\.]*?)['"]\s*?;?/;
|
|
335
345
|
var versionCodeRegex = () => /const\s+VERSION_CODE\s*?=\s*?(\d+)\s*?;?/;
|
|
336
346
|
async function parseBinaryVersions() {
|
|
@@ -388,13 +398,65 @@ async function parseBinaryVersions() {
|
|
|
388
398
|
}
|
|
389
399
|
}
|
|
390
400
|
|
|
391
|
-
// src/util/
|
|
392
|
-
|
|
393
|
-
|
|
401
|
+
// src/util/parseConfigFile.ts
|
|
402
|
+
import { is } from "@mj-studio/js-util";
|
|
403
|
+
async function parseConfigFile() {
|
|
404
|
+
const candidates = [
|
|
405
|
+
join2(OptionHolder.resourcesDir, "expo-release-it.config.json"),
|
|
406
|
+
join2(OptionHolder.projectDir, "expo-release-it.config.json")
|
|
407
|
+
];
|
|
408
|
+
if (OptionHolder.input.config) {
|
|
409
|
+
candidates.unshift(OptionHolder.input.config);
|
|
410
|
+
}
|
|
411
|
+
const validConfigFilePath = candidates.find(
|
|
412
|
+
(candidate) => exist(candidate) && is.object(readJsonSlow(candidate))
|
|
413
|
+
);
|
|
414
|
+
if (!validConfigFilePath) return;
|
|
415
|
+
const config = readJsonSlow(validConfigFilePath);
|
|
416
|
+
assignIfValueIsValidAndNotSetAlready(
|
|
417
|
+
OptionHolder.input,
|
|
418
|
+
"semverIncrement",
|
|
419
|
+
config.bump?.increment
|
|
420
|
+
);
|
|
421
|
+
assignIfValueIsValidAndNotSetAlready(
|
|
422
|
+
OptionHolder.input,
|
|
423
|
+
"androidOutput",
|
|
424
|
+
config.build?.androidBuildOutput ?? config.upload?.androidBuildOutput
|
|
425
|
+
);
|
|
426
|
+
assignIfValueIsValidAndNotSetAlready(
|
|
427
|
+
OptionHolder.input,
|
|
428
|
+
"uploadMetadata",
|
|
429
|
+
config.upload?.uploadMetadata ?? config.submit?.uploadMetadata
|
|
430
|
+
);
|
|
431
|
+
assignIfValueIsValidAndNotSetAlready(
|
|
432
|
+
OptionHolder.input,
|
|
433
|
+
"uploadScreenshot",
|
|
434
|
+
config.upload?.uploadScreenshot ?? config.submit?.uploadScreenshot
|
|
435
|
+
);
|
|
436
|
+
assignIfValueIsValidAndNotSetAlready(OptionHolder.input.git, "commit", config.bump?.git?.commit);
|
|
437
|
+
assignIfValueIsValidAndNotSetAlready(
|
|
438
|
+
OptionHolder.input.git,
|
|
439
|
+
"commitMessage",
|
|
440
|
+
config.bump?.git?.commitMessage
|
|
441
|
+
);
|
|
442
|
+
assignIfValueIsValidAndNotSetAlready(OptionHolder.input.git, "tag", config.bump?.git?.tag);
|
|
443
|
+
assignIfValueIsValidAndNotSetAlready(
|
|
444
|
+
OptionHolder.input.git,
|
|
445
|
+
"tagName",
|
|
446
|
+
config.bump?.git?.tagName
|
|
447
|
+
);
|
|
448
|
+
assignIfValueIsValidAndNotSetAlready(OptionHolder.input.git, "push", config.bump?.git?.push);
|
|
449
|
+
}
|
|
450
|
+
function assignIfValueIsValidAndNotSetAlready(object, key, value) {
|
|
451
|
+
if (!object[key] && value) {
|
|
452
|
+
object[key] = value;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
394
455
|
|
|
395
456
|
// src/util/setup/setup.ts
|
|
396
457
|
async function setup() {
|
|
397
458
|
await setupBasicOptions();
|
|
459
|
+
await parseConfigFile();
|
|
398
460
|
await hydrateKeyholderFileValues();
|
|
399
461
|
await parseBinaryVersions();
|
|
400
462
|
}
|
|
@@ -435,17 +497,17 @@ async function prepareIos() {
|
|
|
435
497
|
import chalk5 from "chalk";
|
|
436
498
|
|
|
437
499
|
// src/util/calculateElapsed.ts
|
|
438
|
-
import { padZero } from "@mj-studio/js-util";
|
|
500
|
+
import { padZero as padZero2 } from "@mj-studio/js-util";
|
|
439
501
|
function calculateElapsed(t) {
|
|
440
502
|
let seconds = Math.floor((Date.now() - t) / 1e3);
|
|
441
503
|
const minutes = Math.floor(seconds / 60);
|
|
442
504
|
seconds = seconds % 60;
|
|
443
|
-
return `${minutes}:${
|
|
505
|
+
return `${minutes}:${padZero2(seconds)}`;
|
|
444
506
|
}
|
|
445
507
|
|
|
446
508
|
// src/util/input/InqueryInputs.ts
|
|
447
509
|
import { select } from "@inquirer/prompts";
|
|
448
|
-
import { is } from "@mj-studio/js-util";
|
|
510
|
+
import { is as is2 } from "@mj-studio/js-util";
|
|
449
511
|
import chalk4 from "chalk";
|
|
450
512
|
var InqueryInputs = {
|
|
451
513
|
platform: async () => {
|
|
@@ -462,21 +524,6 @@ var InqueryInputs = {
|
|
|
462
524
|
});
|
|
463
525
|
}
|
|
464
526
|
},
|
|
465
|
-
platformAll: async () => {
|
|
466
|
-
if (!OptionHolder.input.platformAll) {
|
|
467
|
-
OptionHolder.input.platformAll = await select({
|
|
468
|
-
message: constructInquirerFormattedMessage({
|
|
469
|
-
name: "Platform",
|
|
470
|
-
explanation: `Platforms to run action`
|
|
471
|
-
}),
|
|
472
|
-
choices: [
|
|
473
|
-
{ name: "all", value: "all", description: "Both" },
|
|
474
|
-
{ name: "ios", value: "ios", description: "Release ios" },
|
|
475
|
-
{ name: "android", value: "android", description: "Release android" }
|
|
476
|
-
]
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
527
|
podinstall: async () => {
|
|
481
528
|
if (OptionHolder.input.platform === "ios") {
|
|
482
529
|
OptionHolder.input.pod = await select({
|
|
@@ -506,7 +553,7 @@ var InqueryInputs = {
|
|
|
506
553
|
}
|
|
507
554
|
},
|
|
508
555
|
uploadMetadata: async () => {
|
|
509
|
-
if (!
|
|
556
|
+
if (!is2.boolean(OptionHolder.input.uploadMetadata)) {
|
|
510
557
|
OptionHolder.input.uploadMetadata = await select({
|
|
511
558
|
message: constructInquirerFormattedMessage({
|
|
512
559
|
name: "Upload Text Metadata(title, description, ...)"
|
|
@@ -519,7 +566,7 @@ var InqueryInputs = {
|
|
|
519
566
|
}
|
|
520
567
|
},
|
|
521
568
|
uploadScreenshot: async () => {
|
|
522
|
-
if (!
|
|
569
|
+
if (!is2.boolean(OptionHolder.input.uploadScreenshot)) {
|
|
523
570
|
OptionHolder.input.uploadScreenshot = await select({
|
|
524
571
|
message: constructInquirerFormattedMessage({
|
|
525
572
|
name: "Upload Screenshots & Images"
|
|
@@ -532,7 +579,7 @@ var InqueryInputs = {
|
|
|
532
579
|
}
|
|
533
580
|
},
|
|
534
581
|
useLiveVersionIos: async () => {
|
|
535
|
-
if (!
|
|
582
|
+
if (!is2.boolean(OptionHolder.input.useLiveVersionIos) && OptionHolder.input.platform === "ios") {
|
|
536
583
|
OptionHolder.input.useLiveVersionIos = await select({
|
|
537
584
|
message: constructInquirerFormattedMessage({
|
|
538
585
|
name: "Download metadatas from live version rather than draft"
|