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.
Files changed (53) hide show
  1. package/README.md +5 -298
  2. package/build/command/build.js +90 -43
  3. package/build/command/build.js.map +1 -1
  4. package/build/command/bump.js +219 -24
  5. package/build/command/bump.js.map +1 -1
  6. package/build/command/init.js +84 -22
  7. package/build/command/init.js.map +1 -1
  8. package/build/command/pull.js +84 -37
  9. package/build/command/pull.js.map +1 -1
  10. package/build/command/submit.js +90 -43
  11. package/build/command/submit.js.map +1 -1
  12. package/build/command/upload.js +90 -43
  13. package/build/command/upload.js.map +1 -1
  14. package/build/index.js +196 -47
  15. package/build/index.js.map +1 -1
  16. package/build/type/ExpoReleaseItConfiguration.d.d.ts +54 -0
  17. package/build/type/ExpoReleaseItConfiguration.d.js +1 -0
  18. package/build/type/ExpoReleaseItConfiguration.d.js.map +1 -0
  19. package/build/util/EnvUtil.d.ts +2 -1
  20. package/build/util/EnvUtil.js +2 -0
  21. package/build/util/EnvUtil.js.map +1 -1
  22. package/build/util/FastlaneOption.js +20 -19
  23. package/build/util/FastlaneOption.js.map +1 -1
  24. package/build/util/MetadataSyncUtil.js +20 -19
  25. package/build/util/MetadataSyncUtil.js.map +1 -1
  26. package/build/util/OptionHolder.d.ts +9 -1
  27. package/build/util/OptionHolder.js +20 -19
  28. package/build/util/OptionHolder.js.map +1 -1
  29. package/build/util/generateAppStoreConnectApiKeyFile.js +20 -19
  30. package/build/util/generateAppStoreConnectApiKeyFile.js.map +1 -1
  31. package/build/util/injectTemplatePlaceHolders.js +20 -19
  32. package/build/util/injectTemplatePlaceHolders.js.map +1 -1
  33. package/build/util/input/InqueryInputs.d.ts +0 -1
  34. package/build/util/input/InqueryInputs.js +20 -34
  35. package/build/util/input/InqueryInputs.js.map +1 -1
  36. package/build/util/parseConfigFile.d.ts +3 -0
  37. package/build/util/parseConfigFile.js +151 -0
  38. package/build/util/parseConfigFile.js.map +1 -0
  39. package/build/util/setup/VersionUtil.d.ts +3 -1
  40. package/build/util/setup/VersionUtil.js +45 -19
  41. package/build/util/setup/VersionUtil.js.map +1 -1
  42. package/build/util/setup/hydrateKeyholderFileValues.js +20 -19
  43. package/build/util/setup/hydrateKeyholderFileValues.js.map +1 -1
  44. package/build/util/setup/prepareAndroid.js +20 -19
  45. package/build/util/setup/prepareAndroid.js.map +1 -1
  46. package/build/util/setup/prepareIos.js +20 -19
  47. package/build/util/setup/prepareIos.js.map +1 -1
  48. package/build/util/setup/setup.js +85 -22
  49. package/build/util/setup/setup.js.map +1 -1
  50. package/build/util/throwError.js +8 -0
  51. package/build/util/throwError.js.map +1 -1
  52. package/expo-release-it.schema.json +77 -0
  53. package/package.json +17 -18
package/build/index.js CHANGED
@@ -6,17 +6,16 @@ var package_default = {
6
6
  name: "expo-release-it",
7
7
  module: "src/index.ts",
8
8
  type: "module",
9
- version: "0.3.1",
9
+ version: "0.4.0",
10
10
  license: "MIT",
11
- homepage: "https://github.com/mym0404/expo-release-it",
11
+ homepage: "https://expo-release-it.mjstudio.net/",
12
12
  repository: "https://github.com/mym0404/expo-release-it",
13
13
  scripts: {
14
- build: "tsup",
15
- dev: "yarn run build && NODE_ENV=development node bin/expo-release-it.mjs",
16
- release: "yarn build && release-it",
17
- android: "expo run:android",
18
- ios: "expo run:ios",
19
- t: "tsc --noEmit -p ."
14
+ build: "pnpm build:json-schema-type && tsup",
15
+ "build:json-schema-type": "json2ts --input expo-release-it.schema.json --output src/type/ExpoReleaseItConfiguration.d.ts",
16
+ dev: "pnpm build && NODE_ENV=development node bin/expo-release-it.mjs",
17
+ release: "pnpm build && pnpm run t && release-it",
18
+ t: "lefthook run check"
20
19
  },
21
20
  dependencies: {
22
21
  "@inquirer/prompts": "^7.4.1",
@@ -26,8 +25,8 @@ var package_default = {
26
25
  execa: "^9.5.2",
27
26
  "fs-extra": "^11.3.0",
28
27
  ora: "^8.2.0",
29
- react: "18.3.1",
30
- "react-native": "0.76.9",
28
+ react: "catalog:native",
29
+ "react-native": "catalog:native",
31
30
  semver: "^7.7.1",
32
31
  url: "^0.11.4"
33
32
  },
@@ -36,29 +35,29 @@ var package_default = {
36
35
  "@release-it/conventional-changelog": "^10.0.1",
37
36
  "@types/fs-extra": "^11.0.4",
38
37
  "@types/semver": "^7.7.0",
38
+ "json-schema-to-typescript": "^15.0.4",
39
39
  lefthook: "^1.11.11",
40
- prettier: "3.5.3",
40
+ prettier: "catalog:",
41
41
  "release-it": "^19.0.1",
42
42
  "tiny-glob": "^0.2.9",
43
43
  tsup: "^8.4.0",
44
- typescript: "^5.8.3"
44
+ typescript: "catalog:",
45
+ vitest: "^3.1.2"
45
46
  },
46
- workspaces: [
47
- "example"
48
- ],
49
47
  bin: "./bin/expo-release-it.mjs",
50
48
  files: [
51
49
  "build",
52
50
  "package.json",
53
51
  "bin",
54
- "template"
52
+ "template",
53
+ "expo-release-it.schema.json"
55
54
  ],
56
- packageManager: "yarn@4.9.1",
57
55
  commitlint: {
58
56
  extends: [
59
57
  "@commitlint/config-conventional"
60
58
  ]
61
- }
59
+ },
60
+ packageManager: "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
62
61
  };
63
62
 
64
63
  // src/util/FileUtil.ts
@@ -127,7 +126,9 @@ var OptionHolder = {
127
126
  rootDir: resolve2(fileURLToPath(import.meta.url), "../.."),
128
127
  templateDir: resolve2(fileURLToPath(import.meta.url), "../../template")
129
128
  },
130
- input: {},
129
+ input: {
130
+ git: {}
131
+ },
131
132
  keyholderMap: {},
132
133
  templateDirNames: ["key"],
133
134
  projectDir: "",
@@ -175,21 +176,6 @@ var InqueryInputs = {
175
176
  });
176
177
  }
177
178
  },
178
- platformAll: async () => {
179
- if (!OptionHolder.input.platformAll) {
180
- OptionHolder.input.platformAll = await select({
181
- message: constructInquirerFormattedMessage({
182
- name: "Platform",
183
- explanation: `Platforms to run action`
184
- }),
185
- choices: [
186
- { name: "all", value: "all", description: "Both" },
187
- { name: "ios", value: "ios", description: "Release ios" },
188
- { name: "android", value: "android", description: "Release android" }
189
- ]
190
- });
191
- }
192
- },
193
179
  podinstall: async () => {
194
180
  if (OptionHolder.input.platform === "ios") {
195
181
  OptionHolder.input.pod = await select({
@@ -294,6 +280,11 @@ async function hydrateKeyholderFileValues() {
294
280
  }
295
281
  }
296
282
 
283
+ // src/util/EnvUtil.ts
284
+ var isDev = process.env.NODE_ENV === "development";
285
+ var isWin = process.platform.startsWith("win");
286
+ var isTest = process.env.NODE_ENV === "test";
287
+
297
288
  // src/util/throwError.ts
298
289
  function throwError(message, e) {
299
290
  if (e) {
@@ -301,11 +292,15 @@ function throwError(message, e) {
301
292
  } else {
302
293
  logger.error(message);
303
294
  }
295
+ if (isTest) {
296
+ throw new Error("throwError");
297
+ }
304
298
  process.exit(1);
305
299
  }
306
300
 
307
301
  // src/util/setup/VersionUtil.ts
308
302
  import semver from "semver";
303
+ import { padZero } from "@mj-studio/js-util";
309
304
  var versionNameRegex = () => /const\s+VERSION_NAME\s*?=\s*?['"]([\d\.]*?)['"]\s*?;?/;
310
305
  var versionCodeRegex = () => /const\s+VERSION_CODE\s*?=\s*?(\d+)\s*?;?/;
311
306
  async function parseBinaryVersions() {
@@ -396,14 +391,80 @@ async function injectBinaryVersions({
396
391
  writeJson(filePath, json);
397
392
  }
398
393
  }
394
+ function checkVersionCodeIsTiedWithVersionName(versionName, versionCode) {
395
+ if (!semver.valid(versionName)) return false;
396
+ return generateVersionCodeTiedWithVersionName(versionName) === versionCode;
397
+ }
398
+ function generateVersionCodeTiedWithVersionName(versionName) {
399
+ if (!semver.valid(versionName))
400
+ throwError(
401
+ "Version Name is not a valid semver format when running `generateVersionCodeTiedWithVersionName`"
402
+ );
403
+ const major = semver.major(versionName);
404
+ const minor = semver.minor(versionName);
405
+ const patch = semver.patch(versionName);
406
+ return `${major}${padZero(minor, 3)}${padZero(patch, 3)}`;
407
+ }
399
408
 
400
- // src/util/EnvUtil.ts
401
- var isDev = process.env.NODE_ENV === "development";
402
- var isWin = process.platform.startsWith("win");
409
+ // src/util/parseConfigFile.ts
410
+ import { is as is2 } from "@mj-studio/js-util";
411
+ async function parseConfigFile() {
412
+ const candidates = [
413
+ join2(OptionHolder.resourcesDir, "expo-release-it.config.json"),
414
+ join2(OptionHolder.projectDir, "expo-release-it.config.json")
415
+ ];
416
+ if (OptionHolder.input.config) {
417
+ candidates.unshift(OptionHolder.input.config);
418
+ }
419
+ const validConfigFilePath = candidates.find(
420
+ (candidate) => exist(candidate) && is2.object(readJsonSlow(candidate))
421
+ );
422
+ if (!validConfigFilePath) return;
423
+ const config = readJsonSlow(validConfigFilePath);
424
+ assignIfValueIsValidAndNotSetAlready(
425
+ OptionHolder.input,
426
+ "semverIncrement",
427
+ config.bump?.increment
428
+ );
429
+ assignIfValueIsValidAndNotSetAlready(
430
+ OptionHolder.input,
431
+ "androidOutput",
432
+ config.build?.androidBuildOutput ?? config.upload?.androidBuildOutput
433
+ );
434
+ assignIfValueIsValidAndNotSetAlready(
435
+ OptionHolder.input,
436
+ "uploadMetadata",
437
+ config.upload?.uploadMetadata ?? config.submit?.uploadMetadata
438
+ );
439
+ assignIfValueIsValidAndNotSetAlready(
440
+ OptionHolder.input,
441
+ "uploadScreenshot",
442
+ config.upload?.uploadScreenshot ?? config.submit?.uploadScreenshot
443
+ );
444
+ assignIfValueIsValidAndNotSetAlready(OptionHolder.input.git, "commit", config.bump?.git?.commit);
445
+ assignIfValueIsValidAndNotSetAlready(
446
+ OptionHolder.input.git,
447
+ "commitMessage",
448
+ config.bump?.git?.commitMessage
449
+ );
450
+ assignIfValueIsValidAndNotSetAlready(OptionHolder.input.git, "tag", config.bump?.git?.tag);
451
+ assignIfValueIsValidAndNotSetAlready(
452
+ OptionHolder.input.git,
453
+ "tagName",
454
+ config.bump?.git?.tagName
455
+ );
456
+ assignIfValueIsValidAndNotSetAlready(OptionHolder.input.git, "push", config.bump?.git?.push);
457
+ }
458
+ function assignIfValueIsValidAndNotSetAlready(object, key, value) {
459
+ if (!object[key] && value) {
460
+ object[key] = value;
461
+ }
462
+ }
403
463
 
404
464
  // src/util/setup/setup.ts
405
465
  async function setup() {
406
466
  await setupBasicOptions();
467
+ await parseConfigFile();
407
468
  await hydrateKeyholderFileValues();
408
469
  await parseBinaryVersions();
409
470
  }
@@ -575,17 +636,33 @@ var yesShell = (command, args = [], options) => {
575
636
  };
576
637
 
577
638
  // src/command/bump.ts
639
+ import { select as select2 } from "@inquirer/prompts";
640
+ import { is as is3 } from "@mj-studio/js-util";
578
641
  async function bump({ options }) {
579
642
  Object.assign(OptionHolder.input, options);
580
643
  await preCheck();
581
644
  await setup();
582
- const nextVersionName = semver2.inc(OptionHolder.versionName, "patch");
583
- const nextVersionCode = Number(OptionHolder.versionCode) + 1 + "";
645
+ const nextVersionName = semver2.inc(OptionHolder.versionName, OptionHolder.input.semverIncrement);
646
+ const nextVersionCode = (() => {
647
+ if (checkVersionCodeIsTiedWithVersionName(OptionHolder.versionName, OptionHolder.versionCode)) {
648
+ return generateVersionCodeTiedWithVersionName(nextVersionName);
649
+ } else {
650
+ logger.warn(
651
+ "version name is not tied with version code like (1.3.5=1003005). Version code is just incremented by 1."
652
+ );
653
+ return Number(OptionHolder.versionCode) + 1 + "";
654
+ }
655
+ })();
584
656
  logger.info(`Next Version: ${nextVersionName}(${nextVersionCode})`);
585
657
  await injectBinaryVersions({ versionName: nextVersionName, versionCode: nextVersionCode });
586
658
  logger.success("Binary versions have been bumped in expo config file");
659
+ await processCommit({ nextVersionName, nextVersionCode });
660
+ if (OptionHolder.input.git.commit) {
661
+ await promptTagAndPush({ nextVersionName, nextVersionCode });
662
+ }
587
663
  }
588
664
  async function preCheck() {
665
+ if (isDev) return;
589
666
  try {
590
667
  let hasChange = false;
591
668
  try {
@@ -600,6 +677,73 @@ async function preCheck() {
600
677
  throwError("Precheck Failed", e);
601
678
  }
602
679
  }
680
+ async function processCommit({
681
+ nextVersionCode,
682
+ nextVersionName
683
+ }) {
684
+ if (!is3.boolean(OptionHolder.input.git.commit)) {
685
+ OptionHolder.input.git.commit = await select2({
686
+ message: constructInquirerFormattedMessage({ name: "Commit?" }),
687
+ choices: [
688
+ { name: "yes", value: true },
689
+ { name: "no", value: false }
690
+ ]
691
+ });
692
+ }
693
+ if (!is3.notEmptyString(OptionHolder.input.git.commitMessage)) {
694
+ OptionHolder.input.git.commitMessage = "chore: release $(version) \u{1F680}";
695
+ }
696
+ if (OptionHolder.input.git.commit) {
697
+ await exe("git", ["add", "--all"]);
698
+ await exe("git", [
699
+ "commit",
700
+ "-m",
701
+ OptionHolder.input.git.commitMessage.replaceAll(
702
+ "$(version)",
703
+ `${nextVersionName}(${nextVersionCode})`
704
+ )
705
+ ]);
706
+ }
707
+ }
708
+ async function promptTagAndPush({
709
+ nextVersionCode,
710
+ nextVersionName
711
+ }) {
712
+ if (!is3.boolean(OptionHolder.input.git.tag)) {
713
+ OptionHolder.input.git.tag = await select2({
714
+ message: constructInquirerFormattedMessage({ name: "Tag?" }),
715
+ choices: [
716
+ { name: "yes", value: true },
717
+ { name: "no", value: false }
718
+ ]
719
+ });
720
+ }
721
+ if (!is3.notEmptyString(OptionHolder.input.git.tagName)) {
722
+ OptionHolder.input.git.tagName = "v$(version)";
723
+ }
724
+ const tagName = OptionHolder.input.git.tagName.replaceAll(
725
+ "$(version)",
726
+ `${nextVersionName}(${nextVersionCode})`
727
+ );
728
+ if (OptionHolder.input.git.tag) {
729
+ await exe("git", ["tag", "-a", tagName, "-m", tagName]);
730
+ }
731
+ if (!is3.boolean(OptionHolder.input.git.push)) {
732
+ OptionHolder.input.git.push = await select2({
733
+ message: constructInquirerFormattedMessage({ name: "Push?" }),
734
+ choices: [
735
+ { name: "yes", value: true },
736
+ { name: "no", value: false }
737
+ ]
738
+ });
739
+ }
740
+ if (OptionHolder.input.git.push) {
741
+ if (OptionHolder.input.git.tag) {
742
+ await exe("git", ["push", "origin", tagName]);
743
+ }
744
+ await exe("git", ["push"]);
745
+ }
746
+ }
603
747
 
604
748
  // src/util/iterateAllFiles.ts
605
749
  async function iterateAllFiles(root, callback) {
@@ -781,12 +925,12 @@ async function prepareIos() {
781
925
  import chalk6 from "chalk";
782
926
 
783
927
  // src/util/calculateElapsed.ts
784
- import { padZero } from "@mj-studio/js-util";
928
+ import { padZero as padZero2 } from "@mj-studio/js-util";
785
929
  function calculateElapsed(t) {
786
930
  let seconds = Math.floor((Date.now() - t) / 1e3);
787
931
  const minutes = Math.floor(seconds / 60);
788
932
  seconds = seconds % 60;
789
- return `${minutes}:${padZero(seconds)}`;
933
+ return `${minutes}:${padZero2(seconds)}`;
790
934
  }
791
935
 
792
936
  // src/util/FastlaneOption.ts
@@ -1070,17 +1214,22 @@ var androidBuildOutputOption = new Option(
1070
1214
  "--androidOutput <output>",
1071
1215
  "Android Build Output"
1072
1216
  ).choices(["aab", "apk"]);
1217
+ var configFileOption = new Option("--config <filePath>", "expo-release-it.config.json path");
1073
1218
  var run = () => {
1074
1219
  const program = new Command();
1075
1220
  program.name("expo-release-it").description(
1076
1221
  "Opinionated Expo CICD workflow CLI for building & uploading & submitting Expo projects on your machine"
1077
1222
  ).version(OptionHolder.cli.version);
1078
- program.command("init").description("Configure resources and environment").action(async (options) => handleError(init({ options })));
1079
- program.command("bump").description("Bump binary release patch version with modifying app.json").action(async (options) => handleError(bump({ options })));
1080
- program.command("build").description("Build artifacts").addOption(platformOption).addOption(androidBuildOutputOption).action(async (options) => handleError(build({ options })));
1081
- 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 text metadatas").option("-s --uploadScreenshot", "Upload store screenshots").action(async (options) => handleError(upload({ options })));
1082
- program.command("submit").description("Submit Google Play Console & App Store Connect Review with latest testing track").addOption(platformOption).option("-m --uploadMetadata", "Upload store text metadatas").option("-s --uploadScreenshot", "Upload store screenshots").action(async (options) => handleError(submit({ options })));
1083
- program.command("pull").description("Download metadatas from stores").addOption(platformOption).option("-l --useLiveVersionIos", "Download metadatas from live version rather than draft").action(async (options) => handleError(pull({ options })));
1223
+ program.command("init").description("Configure resources and environment").addOption(configFileOption).action(async (options) => handleError(init({ options })));
1224
+ program.command("bump").description("Bump binary release patch version with modifying app.json").addOption(
1225
+ new Option("-i --increment <increment>", "Version increment mode").default("patch").choices(["major", "minor", "patch"])
1226
+ ).addOption(configFileOption).action(
1227
+ async (options) => handleError(bump({ options: { ...options, semverIncrement: options.increment } }))
1228
+ );
1229
+ program.command("build").description("Build artifacts").addOption(platformOption).addOption(androidBuildOutputOption).addOption(configFileOption).action(async (options) => handleError(build({ options })));
1230
+ 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 text metadatas").option("-s --uploadScreenshot", "Upload store screenshots").addOption(configFileOption).action(async (options) => handleError(upload({ options })));
1231
+ program.command("submit").description("Submit Google Play Console & App Store Connect Review with latest testing track").addOption(platformOption).option("-m --uploadMetadata", "Upload store text metadatas").option("-s --uploadScreenshot", "Upload store screenshots").addOption(configFileOption).action(async (options) => handleError(submit({ options })));
1232
+ program.command("pull").description("Download metadatas from stores").addOption(platformOption).option("-l --useLiveVersionIos", "Download metadatas from live version rather than draft").addOption(configFileOption).action(async (options) => handleError(pull({ options })));
1084
1233
  program.parse();
1085
1234
  };
1086
1235
  async function handleError(promise) {