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.
Files changed (75) hide show
  1. package/README.md +133 -12
  2. package/build/command/build.js +135 -60
  3. package/build/command/build.js.map +1 -1
  4. package/build/command/bump.js +15 -18
  5. package/build/command/bump.js.map +1 -1
  6. package/build/command/init.js +13 -9
  7. package/build/command/init.js.map +1 -1
  8. package/build/command/pull.js +136 -50
  9. package/build/command/pull.js.map +1 -1
  10. package/build/command/submit.js +135 -55
  11. package/build/command/submit.js.map +1 -1
  12. package/build/command/upload.js +136 -56
  13. package/build/command/upload.js.map +1 -1
  14. package/build/index.js +194 -141
  15. package/build/index.js.map +1 -1
  16. package/build/util/FastlaneOption.js +10 -7
  17. package/build/util/FastlaneOption.js.map +1 -1
  18. package/build/util/MetadataSyncUtil.d.ts +4 -0
  19. package/build/util/MetadataSyncUtil.js +169 -0
  20. package/build/util/MetadataSyncUtil.js.map +1 -0
  21. package/build/util/OptionHolder.d.ts +2 -1
  22. package/build/util/OptionHolder.js +4 -2
  23. package/build/util/OptionHolder.js.map +1 -1
  24. package/build/util/generateAppStoreConnectApiKeyFile.js +5 -3
  25. package/build/util/generateAppStoreConnectApiKeyFile.js.map +1 -1
  26. package/build/util/injectTemplatePlaceHolders.js +14 -21
  27. package/build/util/injectTemplatePlaceHolders.js.map +1 -1
  28. package/build/util/input/InqueryInputs.d.ts +1 -0
  29. package/build/util/input/InqueryInputs.js +19 -2
  30. package/build/util/input/InqueryInputs.js.map +1 -1
  31. package/build/util/setup/VersionUtil.js +10 -12
  32. package/build/util/setup/VersionUtil.js.map +1 -1
  33. package/build/util/setup/hydrateKeyholderFileValues.js +4 -2
  34. package/build/util/setup/hydrateKeyholderFileValues.js.map +1 -1
  35. package/build/util/setup/prepareAndroid.js +56 -28
  36. package/build/util/setup/prepareAndroid.js.map +1 -1
  37. package/build/util/setup/prepareIos.js +61 -27
  38. package/build/util/setup/prepareIos.js.map +1 -1
  39. package/build/util/setup/setup.js +12 -8
  40. package/build/util/setup/setup.js.map +1 -1
  41. package/package.json +3 -1
  42. package/template/android/fastlane/Fastfile +2 -0
  43. package/template/android/fastlane/Appfile +0 -2
  44. package/template/android/fastlane/metadata/android/ko-KR/changelogs/default.txt +0 -1
  45. package/template/android/fastlane/metadata/android/ko-KR/full_description.txt +0 -0
  46. package/template/android/fastlane/metadata/android/ko-KR/short_description.txt +0 -0
  47. package/template/android/fastlane/metadata/android/ko-KR/title.txt +0 -0
  48. package/template/android/fastlane/metadata/android/ko-KR/video.txt +0 -0
  49. package/template/ios/fastlane/metadata/copyright.txt +0 -0
  50. package/template/ios/fastlane/metadata/ko/apple_tv_privacy_policy.txt +0 -0
  51. package/template/ios/fastlane/metadata/ko/description.txt +0 -0
  52. package/template/ios/fastlane/metadata/ko/keywords.txt +0 -0
  53. package/template/ios/fastlane/metadata/ko/marketing_url.txt +0 -0
  54. package/template/ios/fastlane/metadata/ko/name.txt +0 -0
  55. package/template/ios/fastlane/metadata/ko/privacy_url.txt +0 -0
  56. package/template/ios/fastlane/metadata/ko/promotional_text.txt +0 -0
  57. package/template/ios/fastlane/metadata/ko/release_notes.txt +0 -0
  58. package/template/ios/fastlane/metadata/ko/subtitle.txt +0 -0
  59. package/template/ios/fastlane/metadata/ko/support_url.txt +0 -0
  60. package/template/ios/fastlane/metadata/primary_category.txt +0 -0
  61. package/template/ios/fastlane/metadata/primary_first_sub_category.txt +0 -1
  62. package/template/ios/fastlane/metadata/primary_second_sub_category.txt +0 -1
  63. package/template/ios/fastlane/metadata/review_information/demo_password.txt +0 -0
  64. package/template/ios/fastlane/metadata/review_information/demo_user.txt +0 -0
  65. package/template/ios/fastlane/metadata/review_information/email_address.txt +0 -0
  66. package/template/ios/fastlane/metadata/review_information/first_name.txt +0 -0
  67. package/template/ios/fastlane/metadata/review_information/last_name.txt +0 -0
  68. package/template/ios/fastlane/metadata/review_information/notes.txt +0 -1
  69. package/template/ios/fastlane/metadata/review_information/phone_number.txt +0 -0
  70. package/template/ios/fastlane/metadata/secondary_category.txt +0 -1
  71. package/template/ios/fastlane/metadata/secondary_first_sub_category.txt +0 -1
  72. package/template/ios/fastlane/metadata/secondary_second_sub_category.txt +0 -1
  73. package/template/ios/fastlane/screenshots/README.txt +0 -30
  74. package/template/key/android_upload_certificate.pem +0 -2
  75. /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.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(path3) {
60
- return fs.existsSync(path3);
61
+ function exist(path2) {
62
+ return fs.existsSync(path2);
61
63
  }
62
- function isDir(path3) {
63
- return exist(path3) && fs.lstatSync(path3).isDirectory();
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(path3) {
69
- return exist(path3) && fs.lstatSync(path3).isFile();
70
+ function isFile(path2) {
71
+ return exist(path2) && fs.lstatSync(path2).isFile();
70
72
  }
71
- function read(path3) {
72
- return fs.readFileSync(path3, { encoding: "utf8" });
73
+ function read(path2) {
74
+ return fs.readFileSync(path2, { encoding: "utf8" });
73
75
  }
74
- function readdir(path3) {
75
- return fs.readdirSync(path3);
76
+ function readdir(path2) {
77
+ return fs.readdirSync(path2);
76
78
  }
77
- function readJsonSlow(path3) {
78
- return fs.readJSONSync(path3);
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 move(src, dest, options) {
91
- fs.moveSync(src, dest, options);
92
+ function writeJson(path2, json) {
93
+ return write(path2, JSON.stringify(json, null, 2));
92
94
  }
93
- function writeJson(path3, json) {
94
- return write(path3, JSON.stringify(json, null, 2));
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(path3).isDirectory()) {
101
- return fs.rmSync(path3, { force: true, recursive: true });
99
+ if (fs.lstatSync(path2).isDirectory()) {
100
+ return fs.rmSync(path2, { force: true, recursive: true });
102
101
  } else {
103
- return fs.rmSync(path3, { force: true });
102
+ return fs.rmSync(path2, { force: true });
104
103
  }
105
104
  }
106
- async function iterateDir(path3, fn) {
107
- if (!isDir(path3)) {
105
+ async function iterateDir(path2, fn) {
106
+ if (!isDir(path2)) {
108
107
  return;
109
108
  }
110
- for (const file of fs.readdirSync(path3)) {
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
- outputOfInitDir: "",
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 = /const VERSION_NAME = '(.*?)';/.exec(content)?.[1];
280
- const VERSION_CODE = /const VERSION_CODE = (.*?);/.exec(content)?.[1];
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
- /const VERSION_NAME = '(.*?)';/,
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.outputOfInitDir = resolve2(OptionHolder.projectDir, "expo-release-it");
369
- OptionHolder.keyDir = resolve2(OptionHolder.outputOfInitDir, "key");
370
- OptionHolder.keyholderFilePath = resolve2(OptionHolder.outputOfInitDir, "keyholder.json");
371
- OptionHolder.tempDir = resolve2(OptionHolder.outputOfInitDir, ".temp");
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.outputOfInitDir, dir);
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(`next version: ${nextVersionName}(${nextVersionCode})`);
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 })`bundle install`;
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.outputOfInitDir, "key", "android_release_keystore.jks"))}')
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 })`bundle install`;
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 chalk5 from "chalk";
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.outputOfInitDir, "output", "android", "aab", "app-release.aab")}`,
696
- `apk_path:${resolve2(OptionHolder.outputOfInitDir, "output", "android", "apk", "app-release.apk")}`,
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, "ios_testflight_upload_api_key.p8")}`,
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.outputOfInitDir, "output", "ios", "app.ipa")}`,
709
- `ipa_dir:${resolve2(OptionHolder.outputOfInitDir, "output", "ios")}`,
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("Build & Upload Started");
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 ${chalk5.bold.inverse(calculateElapsed(startTime))}`);
794
+ logger.success(`iOS Upload ${chalk6.bold.inverse(calculateElapsed(startTime))}`);
725
795
  } else {
726
796
  await uploadAndroid();
727
- logger.success(`Android Upload ${chalk5.bold.inverse(calculateElapsed(startTime))}`);
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
- })`bundle exec fastlane upload ${getIosFastlaneOptions()}`;
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
- })`bundle exec fastlane upload ${getAndroidFastlaneOptions()}`;
829
+ });
760
830
  }
761
831
  }
762
832
 
763
833
  // src/command/submit.ts
764
- import chalk6 from "chalk";
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 ${chalk6.bold.inverse(calculateElapsed(startTime))}`);
843
+ logger.success(`Appstore Review Submitted ${chalk7.bold.inverse(calculateElapsed(startTime))}`);
775
844
  } else {
776
845
  await submitAndroid();
777
- logger.success(`Playstore Review Submitted ${chalk6.bold.inverse(calculateElapsed(startTime))}`);
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
- })`bundle exec fastlane sumbit ${getIosFastlaneOptions()}`;
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
- })`bundle exec fastlane submit ${getAndroidFastlaneOptions()}`;
870
+ });
802
871
  }
803
872
  }
804
873
 
805
874
  // src/command/build.ts
806
- import chalk7 from "chalk";
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 ${chalk7.bold.inverse(calculateElapsed(startTime))}`);
884
+ logger.success(`iOS Build ${chalk8.bold.inverse(calculateElapsed(startTime))}`);
817
885
  } else {
818
886
  await buildAndroid();
819
- logger.success(`Android Build ${chalk7.bold.inverse(calculateElapsed(startTime))}`);
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.outputOfInitDir, "output", "ios", "app.ipa"))}`
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 spinner(
861
- "Bundle AAB",
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.outputOfInitDir, "output", "android", "aab");
931
+ outputDir = resolve2(OptionHolder.resourcesDir, "output", "android", "aab");
866
932
  } else {
867
- await spinner(
868
- "Bundle APK",
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.outputOfInitDir, "output", "android", "apk");
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, "ios_testflight_upload_api_key.p8")),
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
- const metadataSrcDir = join2(iosDir, "fastlane/metadata");
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("bundle", ["exec", "fastlane", "supply", "init"], { cwd: androidDir });
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("Build & Upload & Submit locally for Expo project").version(OptionHolder.cli.version);
958
- program.command("init").description("Initialize CLI utilities").action(async (options) => {
959
- try {
960
- await init({ options });
961
- } catch (e) {
962
- throwError("Command Failed");
963
- }
964
- });
965
- program.command("bump").description("Bump binary release patch version with modifying app.json").action(async (options) => {
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
  };