expo-release-it 0.1.2 → 0.1.4
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 +133 -12
- package/build/command/build.js +135 -60
- package/build/command/build.js.map +1 -1
- package/build/command/bump.js +15 -18
- package/build/command/bump.js.map +1 -1
- package/build/command/init.js +13 -9
- package/build/command/init.js.map +1 -1
- package/build/command/pull.js +136 -50
- package/build/command/pull.js.map +1 -1
- package/build/command/submit.js +135 -55
- package/build/command/submit.js.map +1 -1
- package/build/command/upload.js +136 -56
- package/build/command/upload.js.map +1 -1
- package/build/index.js +194 -141
- package/build/index.js.map +1 -1
- package/build/util/FastlaneOption.js +10 -7
- package/build/util/FastlaneOption.js.map +1 -1
- package/build/util/MetadataSyncUtil.d.ts +4 -0
- package/build/util/MetadataSyncUtil.js +169 -0
- package/build/util/MetadataSyncUtil.js.map +1 -0
- package/build/util/OptionHolder.d.ts +2 -1
- package/build/util/OptionHolder.js +4 -2
- package/build/util/OptionHolder.js.map +1 -1
- package/build/util/generateAppStoreConnectApiKeyFile.js +5 -3
- package/build/util/generateAppStoreConnectApiKeyFile.js.map +1 -1
- package/build/util/injectTemplatePlaceHolders.js +14 -21
- package/build/util/injectTemplatePlaceHolders.js.map +1 -1
- package/build/util/input/InqueryInputs.d.ts +1 -0
- package/build/util/input/InqueryInputs.js +19 -2
- package/build/util/input/InqueryInputs.js.map +1 -1
- package/build/util/setup/VersionUtil.js +10 -12
- package/build/util/setup/VersionUtil.js.map +1 -1
- package/build/util/setup/hydrateKeyholderFileValues.js +4 -2
- package/build/util/setup/hydrateKeyholderFileValues.js.map +1 -1
- package/build/util/setup/prepareAndroid.js +56 -28
- package/build/util/setup/prepareAndroid.js.map +1 -1
- package/build/util/setup/prepareIos.js +61 -27
- package/build/util/setup/prepareIos.js.map +1 -1
- package/build/util/setup/setup.js +12 -8
- package/build/util/setup/setup.js.map +1 -1
- package/package.json +3 -1
- package/template/android/fastlane/Fastfile +2 -0
- package/template/android/fastlane/Appfile +0 -2
- package/template/android/fastlane/metadata/android/ko-KR/changelogs/default.txt +0 -1
- package/template/android/fastlane/metadata/android/ko-KR/full_description.txt +0 -0
- package/template/android/fastlane/metadata/android/ko-KR/short_description.txt +0 -0
- package/template/android/fastlane/metadata/android/ko-KR/title.txt +0 -0
- package/template/android/fastlane/metadata/android/ko-KR/video.txt +0 -0
- package/template/ios/fastlane/metadata/copyright.txt +0 -0
- package/template/ios/fastlane/metadata/ko/apple_tv_privacy_policy.txt +0 -0
- package/template/ios/fastlane/metadata/ko/description.txt +0 -0
- package/template/ios/fastlane/metadata/ko/keywords.txt +0 -0
- package/template/ios/fastlane/metadata/ko/marketing_url.txt +0 -0
- package/template/ios/fastlane/metadata/ko/name.txt +0 -0
- package/template/ios/fastlane/metadata/ko/privacy_url.txt +0 -0
- package/template/ios/fastlane/metadata/ko/promotional_text.txt +0 -0
- package/template/ios/fastlane/metadata/ko/release_notes.txt +0 -0
- package/template/ios/fastlane/metadata/ko/subtitle.txt +0 -0
- package/template/ios/fastlane/metadata/ko/support_url.txt +0 -0
- package/template/ios/fastlane/metadata/primary_category.txt +0 -0
- package/template/ios/fastlane/metadata/primary_first_sub_category.txt +0 -1
- package/template/ios/fastlane/metadata/primary_second_sub_category.txt +0 -1
- package/template/ios/fastlane/metadata/review_information/demo_password.txt +0 -0
- package/template/ios/fastlane/metadata/review_information/demo_user.txt +0 -0
- package/template/ios/fastlane/metadata/review_information/email_address.txt +0 -0
- package/template/ios/fastlane/metadata/review_information/first_name.txt +0 -0
- package/template/ios/fastlane/metadata/review_information/last_name.txt +0 -0
- package/template/ios/fastlane/metadata/review_information/notes.txt +0 -1
- package/template/ios/fastlane/metadata/review_information/phone_number.txt +0 -0
- package/template/ios/fastlane/metadata/secondary_category.txt +0 -1
- package/template/ios/fastlane/metadata/secondary_first_sub_category.txt +0 -1
- package/template/ios/fastlane/metadata/secondary_second_sub_category.txt +0 -1
- package/template/ios/fastlane/screenshots/README.txt +0 -30
- package/template/key/android_upload_certificate.pem +0 -2
- /package/template/key/{ios_testflight_upload_api_key.p8 → ios_app_store_connect_api_key.p8} +0 -0
package/build/index.js
CHANGED
|
@@ -6,8 +6,10 @@ var package_default = {
|
|
|
6
6
|
name: "expo-release-it",
|
|
7
7
|
module: "src/index.ts",
|
|
8
8
|
type: "module",
|
|
9
|
-
version: "0.1.
|
|
9
|
+
version: "0.1.3",
|
|
10
10
|
license: "MIT",
|
|
11
|
+
homepage: "https://github.com/mym0404/expo-release-it",
|
|
12
|
+
repository: "https://github.com/mym0404/expo-release-it",
|
|
11
13
|
scripts: {
|
|
12
14
|
build: "tsup",
|
|
13
15
|
dev: "yarn run build && NODE_ENV=development node bin/expo-release-it.mjs",
|
|
@@ -56,26 +58,26 @@ import fs from "fs-extra";
|
|
|
56
58
|
import * as path from "path";
|
|
57
59
|
var join2 = path.join;
|
|
58
60
|
var resolve2 = path.resolve;
|
|
59
|
-
function exist(
|
|
60
|
-
return fs.existsSync(
|
|
61
|
+
function exist(path2) {
|
|
62
|
+
return fs.existsSync(path2);
|
|
61
63
|
}
|
|
62
|
-
function isDir(
|
|
63
|
-
return exist(
|
|
64
|
+
function isDir(path2) {
|
|
65
|
+
return exist(path2) && fs.lstatSync(path2).isDirectory();
|
|
64
66
|
}
|
|
65
67
|
function relativePath(from, to) {
|
|
66
68
|
return path.relative(from, to);
|
|
67
69
|
}
|
|
68
|
-
function isFile(
|
|
69
|
-
return exist(
|
|
70
|
+
function isFile(path2) {
|
|
71
|
+
return exist(path2) && fs.lstatSync(path2).isFile();
|
|
70
72
|
}
|
|
71
|
-
function read(
|
|
72
|
-
return fs.readFileSync(
|
|
73
|
+
function read(path2) {
|
|
74
|
+
return fs.readFileSync(path2, { encoding: "utf8" });
|
|
73
75
|
}
|
|
74
|
-
function readdir(
|
|
75
|
-
return fs.readdirSync(
|
|
76
|
+
function readdir(path2) {
|
|
77
|
+
return fs.readdirSync(path2);
|
|
76
78
|
}
|
|
77
|
-
function readJsonSlow(
|
|
78
|
-
return fs.readJSONSync(
|
|
79
|
+
function readJsonSlow(path2) {
|
|
80
|
+
return fs.readJSONSync(path2);
|
|
79
81
|
}
|
|
80
82
|
function write(p, content) {
|
|
81
83
|
const dir = path.dirname(p);
|
|
@@ -87,27 +89,24 @@ function write(p, content) {
|
|
|
87
89
|
function copy(src, dest, options) {
|
|
88
90
|
fs.copySync(src, dest, options);
|
|
89
91
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
+
function writeJson(path2, json) {
|
|
93
|
+
return write(path2, JSON.stringify(json, null, 2));
|
|
92
94
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
function remove(path3) {
|
|
97
|
-
if (!exist(path3)) {
|
|
95
|
+
function remove(path2) {
|
|
96
|
+
if (!exist(path2)) {
|
|
98
97
|
return;
|
|
99
98
|
}
|
|
100
|
-
if (fs.lstatSync(
|
|
101
|
-
return fs.rmSync(
|
|
99
|
+
if (fs.lstatSync(path2).isDirectory()) {
|
|
100
|
+
return fs.rmSync(path2, { force: true, recursive: true });
|
|
102
101
|
} else {
|
|
103
|
-
return fs.rmSync(
|
|
102
|
+
return fs.rmSync(path2, { force: true });
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
|
-
async function iterateDir(
|
|
107
|
-
if (!isDir(
|
|
105
|
+
async function iterateDir(path2, fn) {
|
|
106
|
+
if (!isDir(path2)) {
|
|
108
107
|
return;
|
|
109
108
|
}
|
|
110
|
-
for (const file of fs.readdirSync(
|
|
109
|
+
for (const file of fs.readdirSync(path2)) {
|
|
111
110
|
await fn(file);
|
|
112
111
|
}
|
|
113
112
|
}
|
|
@@ -124,7 +123,7 @@ var OptionHolder = {
|
|
|
124
123
|
keyholderMap: {},
|
|
125
124
|
templateDirNames: ["key"],
|
|
126
125
|
projectDir: "",
|
|
127
|
-
|
|
126
|
+
resourcesDir: "",
|
|
128
127
|
keyDir: "",
|
|
129
128
|
keyholderFilePath: "",
|
|
130
129
|
versionName: "",
|
|
@@ -168,6 +167,21 @@ var InqueryInputs = {
|
|
|
168
167
|
});
|
|
169
168
|
}
|
|
170
169
|
},
|
|
170
|
+
platformAll: async () => {
|
|
171
|
+
if (!OptionHolder.input.platformAll) {
|
|
172
|
+
OptionHolder.input.platformAll = await select({
|
|
173
|
+
message: constructInquirerFormattedMessage({
|
|
174
|
+
name: "Platform",
|
|
175
|
+
explanation: `Platforms to run action`
|
|
176
|
+
}),
|
|
177
|
+
choices: [
|
|
178
|
+
{ name: "all", value: "all", description: "Both" },
|
|
179
|
+
{ name: "ios", value: "ios", description: "Release ios" },
|
|
180
|
+
{ name: "android", value: "android", description: "Release android" }
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
},
|
|
171
185
|
podinstall: async () => {
|
|
172
186
|
if (OptionHolder.input.platform === "ios") {
|
|
173
187
|
OptionHolder.input.pod = await select({
|
|
@@ -258,6 +272,8 @@ function throwError(message, e) {
|
|
|
258
272
|
|
|
259
273
|
// src/util/setup/VersionUtil.ts
|
|
260
274
|
import semver from "semver";
|
|
275
|
+
var versionNameRegex = () => /const\s+VERSION_NAME\s*?=\s*?['"]([\d\.]*?)['"]\s*?;?/;
|
|
276
|
+
var versionCodeRegex = () => /const\s+VERSION_CODE\s*?=\s*?(\d+)\s*?;?/;
|
|
261
277
|
async function parseBinaryVersions() {
|
|
262
278
|
const files = readdir(OptionHolder.projectDir);
|
|
263
279
|
const jsConfigFiles = ["app.config.ts", "app.config.js", "app.config.cjs", "app.config.mjs"];
|
|
@@ -276,8 +292,8 @@ async function parseBinaryVersions() {
|
|
|
276
292
|
async function parseFromJsConfigFile(filename) {
|
|
277
293
|
const filePath = resolve2(OptionHolder.projectDir, filename);
|
|
278
294
|
const content = read(filePath);
|
|
279
|
-
const VERSION_NAME =
|
|
280
|
-
const VERSION_CODE =
|
|
295
|
+
const VERSION_NAME = versionNameRegex().exec(content)?.[1];
|
|
296
|
+
const VERSION_CODE = versionCodeRegex().exec(content)?.[1];
|
|
281
297
|
if (!VERSION_NAME) {
|
|
282
298
|
throwError("cannot parse version name");
|
|
283
299
|
}
|
|
@@ -333,14 +349,8 @@ async function injectBinaryVersions({
|
|
|
333
349
|
async function injectToJsConfigFile(filename) {
|
|
334
350
|
const filePath = resolve2(OptionHolder.projectDir, filename);
|
|
335
351
|
let content = read(filePath);
|
|
336
|
-
content = content.replace(
|
|
337
|
-
|
|
338
|
-
`const VERSION_NAME = '${versionName}';`
|
|
339
|
-
);
|
|
340
|
-
content = content.replace(
|
|
341
|
-
/const VERSION_CODE = (.*?);/,
|
|
342
|
-
`const VERSION_CODE = ${versionCode};`
|
|
343
|
-
);
|
|
352
|
+
content = content.replace(versionNameRegex(), `const VERSION_NAME = '${versionName}';`);
|
|
353
|
+
content = content.replace(versionCodeRegex(), `const VERSION_CODE = ${versionCode};`);
|
|
344
354
|
write(filePath, content);
|
|
345
355
|
}
|
|
346
356
|
async function injectToJsonConfigFile(filename) {
|
|
@@ -365,10 +375,10 @@ async function setup() {
|
|
|
365
375
|
}
|
|
366
376
|
async function setupBasicOptions() {
|
|
367
377
|
OptionHolder.projectDir = isDev ? resolve2("example") : resolve2(".");
|
|
368
|
-
OptionHolder.
|
|
369
|
-
OptionHolder.keyDir = resolve2(OptionHolder.
|
|
370
|
-
OptionHolder.keyholderFilePath = resolve2(OptionHolder.
|
|
371
|
-
OptionHolder.tempDir = resolve2(OptionHolder.
|
|
378
|
+
OptionHolder.resourcesDir = resolve2(OptionHolder.projectDir, "expo-release-it");
|
|
379
|
+
OptionHolder.keyDir = resolve2(OptionHolder.resourcesDir, "key");
|
|
380
|
+
OptionHolder.keyholderFilePath = resolve2(OptionHolder.resourcesDir, "keyholder.json");
|
|
381
|
+
OptionHolder.tempDir = resolve2(OptionHolder.resourcesDir, ".temp");
|
|
372
382
|
}
|
|
373
383
|
|
|
374
384
|
// src/command/init.ts
|
|
@@ -507,7 +517,7 @@ async function copyTemplates() {
|
|
|
507
517
|
}
|
|
508
518
|
async function copyDirRecursively(dir) {
|
|
509
519
|
const sourceDirPath = join2(OptionHolder.cli.templateDir, dir);
|
|
510
|
-
const destDirPath = join2(OptionHolder.
|
|
520
|
+
const destDirPath = join2(OptionHolder.resourcesDir, dir);
|
|
511
521
|
copy(sourceDirPath, destDirPath, { overwrite: dir !== "key" });
|
|
512
522
|
}
|
|
513
523
|
}
|
|
@@ -535,10 +545,9 @@ async function bump({ options }) {
|
|
|
535
545
|
Object.assign(OptionHolder.input, options);
|
|
536
546
|
await preCheck();
|
|
537
547
|
await setup();
|
|
538
|
-
logger.info(`current version: ${OptionHolder.versionName}(${OptionHolder.versionCode})`);
|
|
539
548
|
const nextVersionName = semver2.inc(OptionHolder.versionName, "patch");
|
|
540
549
|
const nextVersionCode = Number(OptionHolder.versionCode) + 1 + "";
|
|
541
|
-
logger.info(`
|
|
550
|
+
logger.info(`Next Version: ${nextVersionName}(${nextVersionCode})`);
|
|
542
551
|
await injectBinaryVersions({ versionName: nextVersionName, versionCode: nextVersionCode });
|
|
543
552
|
logger.success("Binary versions have been bumped in expo config file");
|
|
544
553
|
}
|
|
@@ -574,18 +583,12 @@ async function iterateAllFiles(root, callback) {
|
|
|
574
583
|
}
|
|
575
584
|
|
|
576
585
|
// src/util/injectTemplatePlaceHolders.ts
|
|
577
|
-
import * as path2 from "node:path";
|
|
578
586
|
async function injectTemplatePlaceHolders(root) {
|
|
579
587
|
await iterateAllFiles(root, async (filePath) => {
|
|
580
|
-
const dirPath = path2.dirname(filePath);
|
|
581
588
|
let content = read(filePath);
|
|
582
589
|
for (const [key, value] of Object.entries(OptionHolder.keyholderMap)) {
|
|
583
590
|
content = content.replaceAll(`{{${key}}}`, value);
|
|
584
591
|
}
|
|
585
|
-
content = content.replaceAll(
|
|
586
|
-
"{{key_dir_relative_path}}",
|
|
587
|
-
relativePath(dirPath, OptionHolder.keyDir)
|
|
588
|
-
);
|
|
589
592
|
write(filePath, content);
|
|
590
593
|
});
|
|
591
594
|
}
|
|
@@ -601,6 +604,71 @@ async function spinner(text, promise) {
|
|
|
601
604
|
});
|
|
602
605
|
}
|
|
603
606
|
|
|
607
|
+
// src/util/MetadataSyncUtil.ts
|
|
608
|
+
import chalk5 from "chalk";
|
|
609
|
+
function copyIosMetadata(to) {
|
|
610
|
+
const iosDir = join2(OptionHolder.projectDir, "ios");
|
|
611
|
+
const nativeDir = join2(iosDir, "fastlane");
|
|
612
|
+
const metadataNativeDir = join2(nativeDir, "metadata");
|
|
613
|
+
const screenshotsNativeDir = join2(nativeDir, "screenshots");
|
|
614
|
+
const resourcesDir = join2(OptionHolder.resourcesDir, "metadata/ios");
|
|
615
|
+
const metadataResourcesDir = join2(resourcesDir, "metadata");
|
|
616
|
+
const screenshotsResourcesDir = join2(resourcesDir, "screenshots");
|
|
617
|
+
if (to === "resources") {
|
|
618
|
+
if (exist(metadataNativeDir) && exist(screenshotsNativeDir)) {
|
|
619
|
+
copy(metadataNativeDir, metadataResourcesDir);
|
|
620
|
+
copy(screenshotsNativeDir, screenshotsResourcesDir);
|
|
621
|
+
logger.done(
|
|
622
|
+
`iOS Metadata saved in ${chalk5.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}. You can edit inside contents.`
|
|
623
|
+
);
|
|
624
|
+
} else {
|
|
625
|
+
logger.warn(
|
|
626
|
+
`iOS Metadata not found in ${chalk5.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
} else {
|
|
630
|
+
if (exist(metadataResourcesDir) && exist(screenshotsResourcesDir)) {
|
|
631
|
+
copy(metadataResourcesDir, metadataNativeDir);
|
|
632
|
+
copy(screenshotsResourcesDir, screenshotsNativeDir);
|
|
633
|
+
logger.done(
|
|
634
|
+
`iOS Metadata copyed to ${chalk5.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`
|
|
635
|
+
);
|
|
636
|
+
} else {
|
|
637
|
+
logger.warn(
|
|
638
|
+
`iOS Metadata not found in ${chalk5.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function copyAndroidMetadata(to) {
|
|
644
|
+
const androidDir = join2(OptionHolder.projectDir, "android");
|
|
645
|
+
const nativeDir = join2(androidDir, "fastlane/metadata/android");
|
|
646
|
+
const resourcesDir = join2(OptionHolder.resourcesDir, "metadata/android");
|
|
647
|
+
if (to === "resouces") {
|
|
648
|
+
if (exist(nativeDir)) {
|
|
649
|
+
copy(nativeDir, resourcesDir);
|
|
650
|
+
logger.done(
|
|
651
|
+
`Android Metadata saved in ${chalk5.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}. You can edit inside contents.`
|
|
652
|
+
);
|
|
653
|
+
} else {
|
|
654
|
+
logger.warn(
|
|
655
|
+
`Android Metadata not found in ${chalk5.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
} else {
|
|
659
|
+
if (exist(resourcesDir)) {
|
|
660
|
+
copy(resourcesDir, nativeDir);
|
|
661
|
+
logger.done(
|
|
662
|
+
`Android Metadata copyed to ${chalk5.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`
|
|
663
|
+
);
|
|
664
|
+
} else {
|
|
665
|
+
logger.warn(
|
|
666
|
+
`Android Metadata not found in ${chalk5.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}`
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
604
672
|
// src/util/setup/prepareAndroid.ts
|
|
605
673
|
async function prepareAndroid() {
|
|
606
674
|
const srcDir = resolve2(OptionHolder.cli.templateDir, "android");
|
|
@@ -622,8 +690,9 @@ async function prepareAndroid() {
|
|
|
622
690
|
"Hydrate template placeholders",
|
|
623
691
|
injectTemplatePlaceHolders(resolve2(destDir, "fastlane"))
|
|
624
692
|
);
|
|
625
|
-
await exe({ cwd: destDir })
|
|
693
|
+
await exe("bundle", ["install"], { cwd: destDir });
|
|
626
694
|
logger.success("Bunder Install - Done");
|
|
695
|
+
copyAndroidMetadata("native");
|
|
627
696
|
}
|
|
628
697
|
async function replaceAndroidSigningConfig(destDir) {
|
|
629
698
|
const buildGradleDirPath = resolve2(destDir, "app");
|
|
@@ -638,7 +707,7 @@ async function replaceAndroidSigningConfig(destDir) {
|
|
|
638
707
|
`
|
|
639
708
|
signingConfigs {
|
|
640
709
|
debug {
|
|
641
|
-
storeFile file('${relativePath(buildGradleDirPath, resolve2(OptionHolder.
|
|
710
|
+
storeFile file('${relativePath(buildGradleDirPath, resolve2(OptionHolder.resourcesDir, "key", "android_release.keystore"))}')
|
|
642
711
|
storePassword '${android_keystore_store_password}'
|
|
643
712
|
keyAlias '${android_keystore_key_alias}'
|
|
644
713
|
keyPassword '${android_keystore_key_password}'
|
|
@@ -669,12 +738,13 @@ async function prepareIos() {
|
|
|
669
738
|
"Hydrate template placeholders",
|
|
670
739
|
injectTemplatePlaceHolders(resolve2(destDir, "fastlane"))
|
|
671
740
|
);
|
|
672
|
-
await exe({ cwd: destDir })
|
|
741
|
+
await exe("bundle", ["install"], { cwd: destDir });
|
|
673
742
|
logger.success("Bunder Install - Done");
|
|
743
|
+
copyIosMetadata("native");
|
|
674
744
|
}
|
|
675
745
|
|
|
676
746
|
// src/command/upload.ts
|
|
677
|
-
import
|
|
747
|
+
import chalk6 from "chalk";
|
|
678
748
|
|
|
679
749
|
// src/util/calculateElapsed.ts
|
|
680
750
|
import { padZero } from "@mj-studio/js-util";
|
|
@@ -689,11 +759,12 @@ function calculateElapsed(t) {
|
|
|
689
759
|
function getAndroidFastlaneOptions() {
|
|
690
760
|
return [
|
|
691
761
|
...Object.entries(OptionHolder.keyholderMap).map(([k, v]) => `${k}:${v}`),
|
|
762
|
+
`json_key:${resolve2(OptionHolder.keyDir, "android_play_console_service_account.json")}`,
|
|
692
763
|
`version_name:${OptionHolder.versionName}`,
|
|
693
764
|
`version_code:${OptionHolder.versionCode}`,
|
|
694
765
|
`upload_metadata:${OptionHolder.input.uploadMetadata}`,
|
|
695
|
-
`aab_path:${resolve2(OptionHolder.
|
|
696
|
-
`apk_path:${resolve2(OptionHolder.
|
|
766
|
+
`aab_path:${resolve2(OptionHolder.resourcesDir, "output", "android", "aab", "app-release.aab")}`,
|
|
767
|
+
`apk_path:${resolve2(OptionHolder.resourcesDir, "output", "android", "apk", "app-release.apk")}`,
|
|
697
768
|
`skip_upload_apk:${OptionHolder.input.androidOutput !== "apk"}`,
|
|
698
769
|
`skip_upload_aab:${OptionHolder.input.androidOutput !== "aab"}`
|
|
699
770
|
];
|
|
@@ -703,10 +774,10 @@ function getIosFastlaneOptions() {
|
|
|
703
774
|
...Object.entries(OptionHolder.keyholderMap).map(([k, v]) => `${k}:${v}`),
|
|
704
775
|
`version_name:${OptionHolder.versionName}`,
|
|
705
776
|
`version_code:${OptionHolder.versionCode}`,
|
|
706
|
-
`api_key_filepath:${resolve2(OptionHolder.keyDir, "
|
|
777
|
+
`api_key_filepath:${resolve2(OptionHolder.keyDir, "ios_app_store_connect_api_key.p8")}`,
|
|
707
778
|
`upload_metadata:${OptionHolder.input.uploadMetadata}`,
|
|
708
|
-
`ipa_path:${resolve2(OptionHolder.
|
|
709
|
-
`ipa_dir:${resolve2(OptionHolder.
|
|
779
|
+
`ipa_path:${resolve2(OptionHolder.resourcesDir, "output", "ios", "app.ipa")}`,
|
|
780
|
+
`ipa_dir:${resolve2(OptionHolder.resourcesDir, "output", "ios")}`,
|
|
710
781
|
`ipa_name:app.ipa`
|
|
711
782
|
];
|
|
712
783
|
}
|
|
@@ -717,14 +788,13 @@ async function upload({ options }) {
|
|
|
717
788
|
const startTime = Date.now();
|
|
718
789
|
await setup();
|
|
719
790
|
await promptInputs2();
|
|
720
|
-
logger.info("
|
|
721
|
-
logger.info(`Version: ${OptionHolder.versionName}(${OptionHolder.versionCode})`);
|
|
791
|
+
logger.info("Upload Testing Track Started");
|
|
722
792
|
if (OptionHolder.input.platform === "ios") {
|
|
723
793
|
await uploadIos();
|
|
724
|
-
logger.success(`iOS Upload ${
|
|
794
|
+
logger.success(`iOS Upload ${chalk6.bold.inverse(calculateElapsed(startTime))}`);
|
|
725
795
|
} else {
|
|
726
796
|
await uploadAndroid();
|
|
727
|
-
logger.success(`Android Upload ${
|
|
797
|
+
logger.success(`Android Upload ${chalk6.bold.inverse(calculateElapsed(startTime))}`);
|
|
728
798
|
}
|
|
729
799
|
}
|
|
730
800
|
async function promptInputs2() {
|
|
@@ -742,39 +812,38 @@ async function uploadIos() {
|
|
|
742
812
|
await prepareIos();
|
|
743
813
|
await fastlane();
|
|
744
814
|
async function fastlane() {
|
|
745
|
-
await exe({
|
|
815
|
+
await exe("bundle", ["exec", "fastlane", "upload", ...getIosFastlaneOptions()], {
|
|
746
816
|
cwd: iosDir,
|
|
747
817
|
env: {
|
|
748
818
|
MATCH_PASSWORD: OptionHolder.keyholderMap.ios_match_password
|
|
749
819
|
}
|
|
750
|
-
})
|
|
820
|
+
});
|
|
751
821
|
}
|
|
752
822
|
}
|
|
753
823
|
async function uploadAndroid() {
|
|
754
824
|
await prepareAndroid();
|
|
755
825
|
await fastlane();
|
|
756
826
|
async function fastlane() {
|
|
757
|
-
await exe({
|
|
827
|
+
await exe("bundle", ["exec", "fastlane", "upload", ...getAndroidFastlaneOptions()], {
|
|
758
828
|
cwd: resolve2(OptionHolder.projectDir, "android")
|
|
759
|
-
})
|
|
829
|
+
});
|
|
760
830
|
}
|
|
761
831
|
}
|
|
762
832
|
|
|
763
833
|
// src/command/submit.ts
|
|
764
|
-
import
|
|
834
|
+
import chalk7 from "chalk";
|
|
765
835
|
async function submit({ options }) {
|
|
766
836
|
Object.assign(OptionHolder.input, options);
|
|
767
837
|
const startTime = Date.now();
|
|
768
838
|
await setup();
|
|
769
839
|
await promptInputs3();
|
|
770
840
|
logger.info("Submit Started");
|
|
771
|
-
logger.info(`Version: ${OptionHolder.versionName}(${OptionHolder.versionCode})`);
|
|
772
841
|
if (OptionHolder.input.platform === "ios") {
|
|
773
842
|
await submitIos();
|
|
774
|
-
logger.success(`Appstore Review Submitted ${
|
|
843
|
+
logger.success(`Appstore Review Submitted ${chalk7.bold.inverse(calculateElapsed(startTime))}`);
|
|
775
844
|
} else {
|
|
776
845
|
await submitAndroid();
|
|
777
|
-
logger.success(`Playstore Review Submitted ${
|
|
846
|
+
logger.success(`Playstore Review Submitted ${chalk7.bold.inverse(calculateElapsed(startTime))}`);
|
|
778
847
|
}
|
|
779
848
|
}
|
|
780
849
|
async function promptInputs3() {
|
|
@@ -785,9 +854,9 @@ async function submitAndroid() {
|
|
|
785
854
|
await prepareAndroid();
|
|
786
855
|
await fastlane();
|
|
787
856
|
async function fastlane() {
|
|
788
|
-
await exe({
|
|
857
|
+
await exe("bundle", ["exec", "fastlane", "submit", ...getIosFastlaneOptions()], {
|
|
789
858
|
cwd: resolve2(OptionHolder.projectDir, "android")
|
|
790
|
-
})
|
|
859
|
+
});
|
|
791
860
|
}
|
|
792
861
|
}
|
|
793
862
|
async function submitIos() {
|
|
@@ -796,27 +865,26 @@ async function submitIos() {
|
|
|
796
865
|
await fastlane();
|
|
797
866
|
async function fastlane() {
|
|
798
867
|
remove(resolve2(iosDir, ".xcode.env.local"));
|
|
799
|
-
await exe({
|
|
868
|
+
await exe("bundle", ["exec", "fastlane", "submit", ...getAndroidFastlaneOptions()], {
|
|
800
869
|
cwd: iosDir
|
|
801
|
-
})
|
|
870
|
+
});
|
|
802
871
|
}
|
|
803
872
|
}
|
|
804
873
|
|
|
805
874
|
// src/command/build.ts
|
|
806
|
-
import
|
|
875
|
+
import chalk8 from "chalk";
|
|
807
876
|
async function build({ options }) {
|
|
808
877
|
Object.assign(OptionHolder.input, options);
|
|
809
878
|
const startTime = Date.now();
|
|
810
879
|
await setup();
|
|
811
880
|
await promptInputs4();
|
|
812
881
|
logger.info("Build Started");
|
|
813
|
-
logger.info(`Version: ${OptionHolder.versionName}(${OptionHolder.versionCode})`);
|
|
814
882
|
if (OptionHolder.input.platform === "ios") {
|
|
815
883
|
await buildIos();
|
|
816
|
-
logger.success(`iOS Build ${
|
|
884
|
+
logger.success(`iOS Build ${chalk8.bold.inverse(calculateElapsed(startTime))}`);
|
|
817
885
|
} else {
|
|
818
886
|
await buildAndroid();
|
|
819
|
-
logger.success(`Android Build ${
|
|
887
|
+
logger.success(`Android Build ${chalk8.bold.inverse(calculateElapsed(startTime))}`);
|
|
820
888
|
}
|
|
821
889
|
}
|
|
822
890
|
async function promptInputs4() {
|
|
@@ -842,7 +910,7 @@ async function buildIos() {
|
|
|
842
910
|
remove(resolve2(iosDir, ".xcode.env.local"));
|
|
843
911
|
await exeEnv("bundle", ["exec", "fastlane", "build", ...getIosFastlaneOptions()]);
|
|
844
912
|
logger.success(
|
|
845
|
-
`artifact generated: ${relativePath(OptionHolder.projectDir, resolve2(OptionHolder.
|
|
913
|
+
`artifact generated: ${relativePath(OptionHolder.projectDir, resolve2(OptionHolder.resourcesDir, "output", "ios", "app.ipa"))}`
|
|
846
914
|
);
|
|
847
915
|
}
|
|
848
916
|
}
|
|
@@ -857,19 +925,15 @@ async function buildAndroid() {
|
|
|
857
925
|
let buildOutputDir;
|
|
858
926
|
let outputDir;
|
|
859
927
|
if (OptionHolder.input.androidOutput === "aab") {
|
|
860
|
-
await
|
|
861
|
-
|
|
862
|
-
exeEnv(isWin ? "gradle.bat" : "./gradlew", ["app:bundleRelease"])
|
|
863
|
-
);
|
|
928
|
+
await exeEnv(isWin ? "gradle.bat" : "./gradlew", ["app:bundleRelease"]);
|
|
929
|
+
logger.done("Bundle AAB");
|
|
864
930
|
buildOutputDir = resolve2(androidDir, "app", "build", "outputs", "bundle", "release");
|
|
865
|
-
outputDir = resolve2(OptionHolder.
|
|
931
|
+
outputDir = resolve2(OptionHolder.resourcesDir, "output", "android", "aab");
|
|
866
932
|
} else {
|
|
867
|
-
await
|
|
868
|
-
|
|
869
|
-
exeEnv(isWin ? "gradle.bat" : "./gradlew", ["app:assembleRelease"])
|
|
870
|
-
);
|
|
933
|
+
await exeEnv(isWin ? "gradle.bat" : "./gradlew", ["app:assembleRelease"]);
|
|
934
|
+
logger.done("Assemble APK");
|
|
871
935
|
buildOutputDir = resolve2(androidDir, "app", "build", "outputs", "apk", "release");
|
|
872
|
-
outputDir = resolve2(OptionHolder.
|
|
936
|
+
outputDir = resolve2(OptionHolder.resourcesDir, "output", "android", "apk");
|
|
873
937
|
}
|
|
874
938
|
remove(outputDir);
|
|
875
939
|
copy(buildOutputDir, outputDir);
|
|
@@ -880,7 +944,7 @@ async function buildAndroid() {
|
|
|
880
944
|
// src/util/generateAppStoreConnectApiKeyFile.ts
|
|
881
945
|
function generateAppStoreConnectApiKeyFile() {
|
|
882
946
|
const json = {
|
|
883
|
-
key: read(resolve2(OptionHolder.keyDir, "
|
|
947
|
+
key: read(resolve2(OptionHolder.keyDir, "ios_app_store_connect_api_key.p8")),
|
|
884
948
|
key_id: OptionHolder.keyholderMap.ios_app_store_connect_api_key_id,
|
|
885
949
|
issuer_id: OptionHolder.keyholderMap.ios_app_store_connect_api_key_issuer_id
|
|
886
950
|
};
|
|
@@ -930,20 +994,30 @@ async function pullIosMetadata() {
|
|
|
930
994
|
"--api_key_path",
|
|
931
995
|
generateAppStoreConnectApiKeyFile()
|
|
932
996
|
]);
|
|
933
|
-
|
|
934
|
-
const screenshotsSrcDir = join2(iosDir, "fastlane/screenshots");
|
|
935
|
-
const metadataDestDir = join2(OptionHolder.outputOfInitDir, "metadata/ios/metadata");
|
|
936
|
-
const screenshotsDestDir = join2(OptionHolder.outputOfInitDir, "metadata/ios/screenshots");
|
|
937
|
-
move(metadataSrcDir, metadataDestDir);
|
|
938
|
-
move(screenshotsSrcDir, screenshotsDestDir);
|
|
997
|
+
copyIosMetadata("resources");
|
|
939
998
|
}
|
|
940
999
|
async function pullAndroidMetadata() {
|
|
941
1000
|
await prepareAndroid();
|
|
942
1001
|
const androidDir = join2(OptionHolder.projectDir, "android");
|
|
943
|
-
await exe(
|
|
1002
|
+
await exe(
|
|
1003
|
+
"bundle",
|
|
1004
|
+
[
|
|
1005
|
+
"exec",
|
|
1006
|
+
"fastlane",
|
|
1007
|
+
"supply",
|
|
1008
|
+
"init",
|
|
1009
|
+
"--json_key",
|
|
1010
|
+
resolve2(OptionHolder.keyDir, "android_play_console_service_account.json"),
|
|
1011
|
+
"--package_name",
|
|
1012
|
+
OptionHolder.keyholderMap.android_package_name
|
|
1013
|
+
],
|
|
1014
|
+
{ cwd: androidDir }
|
|
1015
|
+
);
|
|
1016
|
+
copyAndroidMetadata("resouces");
|
|
944
1017
|
}
|
|
945
1018
|
|
|
946
1019
|
// src/index.ts
|
|
1020
|
+
import { ExecaError } from "execa";
|
|
947
1021
|
var platformOption = new Option("-p --platform <platform>", "Platform").choices([
|
|
948
1022
|
"android",
|
|
949
1023
|
"ios"
|
|
@@ -954,51 +1028,30 @@ var androidBuildOutputOption = new Option(
|
|
|
954
1028
|
).choices(["aab", "apk"]);
|
|
955
1029
|
var run = () => {
|
|
956
1030
|
const program = new Command();
|
|
957
|
-
program.name("expo-release-it").description(
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
});
|
|
965
|
-
program.command("
|
|
966
|
-
try {
|
|
967
|
-
await bump({ options });
|
|
968
|
-
} catch (e) {
|
|
969
|
-
throwError("Command Failed");
|
|
970
|
-
}
|
|
971
|
-
});
|
|
972
|
-
program.command("build").description("Build binary").addOption(platformOption).addOption(androidBuildOutputOption).action(async (options) => {
|
|
973
|
-
try {
|
|
974
|
-
await build({ options });
|
|
975
|
-
} catch (e) {
|
|
976
|
-
throwError("Command Failed", e);
|
|
977
|
-
}
|
|
978
|
-
});
|
|
979
|
-
program.command("upload").description("Upload artifact to play console internal test track(android) and testflight(ios)").addOption(platformOption).addOption(androidBuildOutputOption).option("-m --uploadMetadata", "Upload store metadatas").action(async (options) => {
|
|
980
|
-
try {
|
|
981
|
-
await upload({ options });
|
|
982
|
-
} catch (e) {
|
|
983
|
-
throwError("Command Failed");
|
|
984
|
-
}
|
|
985
|
-
});
|
|
986
|
-
program.command("submit").description("Submit Google Play Console & App Store Connect Review with latest testing track").addOption(platformOption).action(async (options) => {
|
|
987
|
-
try {
|
|
988
|
-
await submit({ options });
|
|
989
|
-
} catch (e) {
|
|
990
|
-
throwError("Command Failed");
|
|
991
|
-
}
|
|
992
|
-
});
|
|
993
|
-
program.command("pull").description("Sync registered metadatas from stores").addOption(platformOption).action(async (options) => {
|
|
994
|
-
try {
|
|
995
|
-
await pull({ options });
|
|
996
|
-
} catch (e) {
|
|
997
|
-
throwError("Command Failed");
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1031
|
+
program.name("expo-release-it").description(
|
|
1032
|
+
"Opinionated Expo CICD workflow CLI for building & uploading & submitting Expo projects on your machine"
|
|
1033
|
+
).version(OptionHolder.cli.version);
|
|
1034
|
+
program.command("init").description("Configure resources and environment").action(async (options) => handleError(init({ options })));
|
|
1035
|
+
program.command("bump").description("Bump binary release patch version with modifying app.json").action(async (options) => handleError(bump({ options })));
|
|
1036
|
+
program.command("build").description("Build binary").addOption(platformOption).addOption(androidBuildOutputOption).action(async (options) => handleError(build({ options })));
|
|
1037
|
+
program.command("upload").description("Upload artifact to play console internal test track(android) and testflight(ios)").addOption(platformOption).addOption(androidBuildOutputOption).option("-m --uploadMetadata", "Upload store metadatas").action(async (options) => handleError(upload({ options })));
|
|
1038
|
+
program.command("submit").description("Submit Google Play Console & App Store Connect Review with latest testing track").addOption(platformOption).action(async (options) => handleError(submit({ options })));
|
|
1039
|
+
program.command("pull").description("Download metadatas from stores").addOption(platformOption).action(async (options) => handleError(pull({ options })));
|
|
1000
1040
|
program.parse();
|
|
1001
1041
|
};
|
|
1042
|
+
async function handleError(promise) {
|
|
1043
|
+
try {
|
|
1044
|
+
return await promise;
|
|
1045
|
+
} catch (e) {
|
|
1046
|
+
if (e instanceof ExecaError) {
|
|
1047
|
+
logger.error(`ExecaError: command: ${e.escapedCommand}`);
|
|
1048
|
+
logger.error(e.message);
|
|
1049
|
+
process.exit(e.exitCode ?? 1);
|
|
1050
|
+
} else {
|
|
1051
|
+
throwError("Command Failed");
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1002
1055
|
export {
|
|
1003
1056
|
run
|
|
1004
1057
|
};
|