@todesktop/cli 1.7.0-4 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1633,6 +1633,11 @@ var full_default = (context) => {
1633
1633
  validSemver: {},
1634
1634
  minLength: 1
1635
1635
  },
1636
+ appBuilderLibVersion: {
1637
+ type: "string",
1638
+ validSemver: {},
1639
+ minLength: 1
1640
+ },
1636
1641
  packageManager: {
1637
1642
  type: "string",
1638
1643
  enum: ["npm", "yarn", "pnpm"]
@@ -1787,6 +1792,7 @@ function computeFullProjectConfig(partialConfig, projectRoot) {
1787
1792
  logger_default.debug("Extends field found, resolving");
1788
1793
  const parentConfigPath = (0, import_path4.resolve)(projectRoot, partialConfig.extends);
1789
1794
  const parentConfig = loadConfig(parentConfigPath);
1795
+ parentConfig.appPath = parentConfig.appPath || ".";
1790
1796
  const parentFullConfig = computeFullProjectConfig(
1791
1797
  parentConfig,
1792
1798
  projectRoot
@@ -1820,7 +1826,6 @@ function getProjectConfig(configPath = null) {
1820
1826
  }
1821
1827
  const projectRoot = (0, import_path5.dirname)(configPath);
1822
1828
  const partialConfig = loadConfig(configPath);
1823
- partialConfig.appPath = partialConfig.appPath || ".";
1824
1829
  const config2 = computeFullProjectConfig(partialConfig, projectRoot);
1825
1830
  validateConfig({ config: config2, projectRoot });
1826
1831
  const result = resolveConfigPaths({ config: config2, projectRoot });
@@ -2283,7 +2288,8 @@ var runBuild_default = async ({ onEvent, shouldCodeSign = true, configPath }) =>
2283
2288
  buildId,
2284
2289
  userId: primaryUserId,
2285
2290
  sourceArchiveDetails,
2286
- nodeVersion: config2.nodeVersion
2291
+ nodeVersion: config2.nodeVersion,
2292
+ appBuilderLibVersion: config2.appBuilderLibVersion
2287
2293
  });
2288
2294
  } catch (e) {
2289
2295
  e.message = `Failed while kicking off build; ${e.message}`;
@@ -2680,33 +2686,34 @@ var ErrorBoundary_default = ErrorBoundary;
2680
2686
  // src/components/OngoingBuildGuard.tsx
2681
2687
  var import_ink20 = require("ink");
2682
2688
  var import_ink_select_input = __toESM(require("ink-select-input"));
2683
- var import_prop_types15 = __toESM(require("prop-types"));
2689
+ var import_prop_types14 = __toESM(require("prop-types"));
2684
2690
  var import_react13 = require("react");
2685
2691
 
2686
2692
  // src/components/CustomSelectInputIndicator.tsx
2687
2693
  var import_ink17 = require("ink");
2688
- var import_prop_types12 = __toESM(require("prop-types"));
2689
2694
  var import_jsx_runtime18 = require("react/jsx-runtime");
2690
- var CustomSelectInputIndicator = ({ isSelected, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink17.Box, { marginRight: 1, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink17.Text, { children: isSelected ? process.platform === "win32" ? ">" : "\u276F" : " " }) });
2691
- CustomSelectInputIndicator.propTypes = {
2692
- isSelected: import_prop_types12.default.bool.isRequired
2693
- };
2694
- var CustomSelectInputIndicator_default = CustomSelectInputIndicator;
2695
+ function CustomSelectInputIndicator({
2696
+ isSelected,
2697
+ ...props
2698
+ }) {
2699
+ const selectIndicator = process.env.NODE_ENV === "test" || process.platform === "win32" ? ">" : "\u276F";
2700
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink17.Box, { marginRight: 1, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink17.Text, { children: isSelected ? selectIndicator : " " }) });
2701
+ }
2695
2702
 
2696
2703
  // src/components/CustomSelectInputItem.tsx
2697
2704
  var import_ink18 = require("ink");
2698
- var import_prop_types13 = __toESM(require("prop-types"));
2705
+ var import_prop_types12 = __toESM(require("prop-types"));
2699
2706
  var import_jsx_runtime19 = require("react/jsx-runtime");
2700
2707
  var CustomSelectInputItem = ({ isSelected, label, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ink18.Text, { bold: isSelected, color: isSelected ? void 0 : "gray", ...props, children: label });
2701
2708
  CustomSelectInputItem.propTypes = {
2702
- isSelected: import_prop_types13.default.bool.isRequired,
2703
- label: import_prop_types13.default.string.isRequired
2709
+ isSelected: import_prop_types12.default.bool.isRequired,
2710
+ label: import_prop_types12.default.string.isRequired
2704
2711
  };
2705
2712
  var CustomSelectInputItem_default = CustomSelectInputItem;
2706
2713
 
2707
2714
  // src/components/ViewBuild.tsx
2708
2715
  var import_ink19 = require("ink");
2709
- var import_prop_types14 = __toESM(require("prop-types"));
2716
+ var import_prop_types13 = __toESM(require("prop-types"));
2710
2717
  var import_react12 = require("react");
2711
2718
 
2712
2719
  // src/utilities/getLatestBuildId.ts
@@ -2896,7 +2903,7 @@ ViewBuild.propTypes = {
2896
2903
  );
2897
2904
  }
2898
2905
  },
2899
- commandUsed: import_prop_types14.default.string.isRequired,
2906
+ commandUsed: import_prop_types13.default.string.isRequired,
2900
2907
  shouldViewLatest: (props, propName, componentName) => {
2901
2908
  if ([props.id, props.shouldViewLatest].filter(Boolean).length !== 1) {
2902
2909
  return new Error(
@@ -2910,7 +2917,7 @@ ViewBuild.propTypes = {
2910
2917
  );
2911
2918
  }
2912
2919
  },
2913
- configPath: import_prop_types14.default.string
2920
+ configPath: import_prop_types13.default.string
2914
2921
  };
2915
2922
  var ViewBuild_default = ViewBuild;
2916
2923
 
@@ -3028,7 +3035,7 @@ var OngoingBuildGuard = ({ children, commandUsed, configPath }) => {
3028
3035
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3029
3036
  import_ink_select_input.default,
3030
3037
  {
3031
- indicatorComponent: CustomSelectInputIndicator_default,
3038
+ indicatorComponent: CustomSelectInputIndicator,
3032
3039
  itemComponent: CustomSelectInputItem_default,
3033
3040
  items,
3034
3041
  onSelect: handleSelect
@@ -3040,9 +3047,9 @@ var OngoingBuildGuard = ({ children, commandUsed, configPath }) => {
3040
3047
  }
3041
3048
  };
3042
3049
  OngoingBuildGuard.propTypes = {
3043
- commandUsed: import_prop_types15.default.string.isRequired,
3044
- children: import_prop_types15.default.oneOfType([import_prop_types15.default.array, import_prop_types15.default.object]),
3045
- configPath: import_prop_types15.default.string
3050
+ commandUsed: import_prop_types14.default.string.isRequired,
3051
+ children: import_prop_types14.default.oneOfType([import_prop_types14.default.array, import_prop_types14.default.object]),
3052
+ configPath: import_prop_types14.default.string
3046
3053
  };
3047
3054
  var OngoingBuildGuard_default = OngoingBuildGuard;
3048
3055
 
@@ -3114,16 +3121,16 @@ var BuildCommand_default = BuildCommand;
3114
3121
 
3115
3122
  // src/components/ViewBuilds.tsx
3116
3123
  var import_ink26 = require("ink");
3117
- var import_prop_types21 = __toESM(require("prop-types"));
3124
+ var import_prop_types20 = __toESM(require("prop-types"));
3118
3125
  var import_react16 = require("react");
3119
3126
 
3120
3127
  // src/components/Table.tsx
3121
3128
  var import_ink24 = require("ink");
3122
- var import_prop_types20 = __toESM(require("prop-types"));
3129
+ var import_prop_types19 = __toESM(require("prop-types"));
3123
3130
 
3124
3131
  // src/components/TableEnd.tsx
3125
3132
  var import_ink21 = require("ink");
3126
- var import_prop_types16 = __toESM(require("prop-types"));
3133
+ var import_prop_types15 = __toESM(require("prop-types"));
3127
3134
  var import_jsx_runtime23 = require("react/jsx-runtime");
3128
3135
  var TableEnd = ({ keyDetails, ...props }) => {
3129
3136
  let content = "\u2514";
@@ -3132,13 +3139,13 @@ var TableEnd = ({ keyDetails, ...props }) => {
3132
3139
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink21.Box, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink21.Text, { children: content }) });
3133
3140
  };
3134
3141
  TableEnd.propTypes = {
3135
- keyDetails: import_prop_types16.default.object.isRequired
3142
+ keyDetails: import_prop_types15.default.object.isRequired
3136
3143
  };
3137
3144
  var TableEnd_default = TableEnd;
3138
3145
 
3139
3146
  // src/components/TableHead.tsx
3140
3147
  var import_ink22 = require("ink");
3141
- var import_prop_types17 = __toESM(require("prop-types"));
3148
+ var import_prop_types16 = __toESM(require("prop-types"));
3142
3149
  var import_react15 = require("react");
3143
3150
  var import_jsx_runtime24 = require("react/jsx-runtime");
3144
3151
  var TableHead = ({ keyDetails, ...props }) => {
@@ -3163,17 +3170,17 @@ var TableHead = ({ keyDetails, ...props }) => {
3163
3170
  ] });
3164
3171
  };
3165
3172
  TableHead.propTypes = {
3166
- bottomLinePrefix: import_prop_types17.default.string,
3167
- keyDetails: import_prop_types17.default.object.isRequired
3173
+ bottomLinePrefix: import_prop_types16.default.string,
3174
+ keyDetails: import_prop_types16.default.object.isRequired
3168
3175
  };
3169
3176
  var TableHead_default = TableHead;
3170
3177
 
3171
3178
  // src/components/TableBody.tsx
3172
- var import_prop_types19 = __toESM(require("prop-types"));
3179
+ var import_prop_types18 = __toESM(require("prop-types"));
3173
3180
 
3174
3181
  // src/components/TableRow.tsx
3175
3182
  var import_ink23 = require("ink");
3176
- var import_prop_types18 = __toESM(require("prop-types"));
3183
+ var import_prop_types17 = __toESM(require("prop-types"));
3177
3184
  var import_jsx_runtime25 = require("react/jsx-runtime");
3178
3185
  var TableRow = ({
3179
3186
  data,
@@ -3211,10 +3218,10 @@ var TableRow = ({
3211
3218
  ] }) });
3212
3219
  };
3213
3220
  TableRow.propTypes = {
3214
- data: import_prop_types18.default.object.isRequired,
3215
- getCellTextProps: import_prop_types18.default.func,
3216
- keyDetails: import_prop_types18.default.object.isRequired,
3217
- textProps: import_prop_types18.default.object
3221
+ data: import_prop_types17.default.object.isRequired,
3222
+ getCellTextProps: import_prop_types17.default.func,
3223
+ keyDetails: import_prop_types17.default.object.isRequired,
3224
+ textProps: import_prop_types17.default.object
3218
3225
  };
3219
3226
  var TableRow_default = TableRow;
3220
3227
 
@@ -3245,8 +3252,8 @@ TableBody.propTypes = {
3245
3252
  );
3246
3253
  }
3247
3254
  },
3248
- getCellTextProps: import_prop_types19.default.func,
3249
- keyDetails: import_prop_types19.default.object.isRequired
3255
+ getCellTextProps: import_prop_types18.default.func,
3256
+ keyDetails: import_prop_types18.default.object.isRequired
3250
3257
  };
3251
3258
  var TableBody_default = TableBody;
3252
3259
 
@@ -3296,7 +3303,7 @@ Table.propTypes = {
3296
3303
  );
3297
3304
  }
3298
3305
  },
3299
- getCellTextProps: import_prop_types20.default.func
3306
+ getCellTextProps: import_prop_types19.default.func
3300
3307
  };
3301
3308
  var Table_default = Table;
3302
3309
 
@@ -3551,11 +3558,11 @@ var removeAppBuilderLibConfig = (builds) => {
3551
3558
  });
3552
3559
  };
3553
3560
  ViewBuilds.propTypes = {
3554
- commandUsed: import_prop_types21.default.string.isRequired,
3555
- configPath: import_prop_types21.default.string,
3556
- count: import_prop_types21.default.number,
3557
- format: import_prop_types21.default.string,
3558
- exit: import_prop_types21.default.bool
3561
+ commandUsed: import_prop_types20.default.string.isRequired,
3562
+ configPath: import_prop_types20.default.string,
3563
+ count: import_prop_types20.default.number,
3564
+ format: import_prop_types20.default.string,
3565
+ exit: import_prop_types20.default.bool
3559
3566
  };
3560
3567
  var ViewBuilds_default = ViewBuilds;
3561
3568
 
@@ -3631,299 +3638,16 @@ var LogoutWrapper = () => {
3631
3638
  };
3632
3639
  var LogoutCommand_default = LogoutWrapper;
3633
3640
 
3634
- // src/commands/ReleaseCommand.tsx
3635
- var import_ink31 = require("ink");
3641
+ // src/components/BuildPicker.tsx
3642
+ var import_ink29 = require("ink");
3643
+ var import_react18 = require("react");
3636
3644
 
3637
- // src/components/ReleaseBuild.tsx
3645
+ // src/components/SelectTable.tsx
3638
3646
  var import_ink28 = require("ink");
3639
- var import_ink_link4 = __toESM(require("ink-link"));
3640
3647
  var import_ink_select_input2 = __toESM(require("ink-select-input"));
3641
- var import_prop_types22 = __toESM(require("prop-types"));
3642
- var import_react18 = require("react");
3643
-
3644
- // src/utilities/getBuildById.ts
3645
- async function getBuildById({
3646
- appId,
3647
- buildId,
3648
- userId
3649
- }) {
3650
- logger_default.debug({ appId, buildId }, "getBuildById");
3651
- const snapshot = await firestore_default.doc(`users/${userId}/applications/${appId}/builds/${buildId}`).get();
3652
- if (!snapshot.exists) {
3653
- return null;
3654
- }
3655
- return snapshot.data();
3656
- }
3657
-
3658
- // src/components/ReleaseBuild.tsx
3648
+ var import_prop_types21 = __toESM(require("prop-types"));
3659
3649
  var import_jsx_runtime32 = require("react/jsx-runtime");
3660
- var getValidationErrorMessageDisplay = (build, validationMessage) => {
3661
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { flexDirection: "column", children: [
3662
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Text, { bold: true, color: "red", children: [
3663
- "Can't release ",
3664
- build.appName,
3665
- " v",
3666
- build.appVersion
3667
- ] }),
3668
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: validationMessage }) }),
3669
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { bold: true, children: "See web UI for more information: " }),
3670
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink_link4.default, { fallback: false, url: build.url, children: build.url }) })
3671
- ] });
3672
- };
3673
- var ReleaseBuild = ({ commandUsed, id, shouldConfirm, configPath }) => {
3674
- const exit = useExit_default();
3675
- const [
3676
- {
3677
- appId,
3678
- arbitraryMessageComponent,
3679
- build,
3680
- error,
3681
- hasConfirmed,
3682
- hasBeenValidatedSuccesfully,
3683
- isComplete,
3684
- isReleasing
3685
- },
3686
- setState
3687
- ] = (0, import_react18.useState)({
3688
- appId: null,
3689
- build: null,
3690
- error: null,
3691
- hasConfirmed: false,
3692
- hasBeenValidatedSuccesfully: false,
3693
- isComplete: false,
3694
- isReleasing: false,
3695
- arbitraryMessageComponent: null
3696
- });
3697
- const onError = (e) => {
3698
- const error2 = e.response ? e.response.data : e;
3699
- logForCI_default(error2);
3700
- setState((prevState) => ({
3701
- ...prevState,
3702
- error: error2
3703
- }));
3704
- };
3705
- (0, import_react18.useEffect)(() => {
3706
- async function releaseBuild() {
3707
- if (build) {
3708
- return;
3709
- }
3710
- const config2 = getProjectConfig(configPath).config;
3711
- const appId2 = config2.id;
3712
- const { id: userId } = await findAppUserId_default(appId2);
3713
- const loadBuild = (buildId) => {
3714
- getBuildById({ appId: appId2, buildId, userId }).then((buildResult) => {
3715
- if (!buildResult) {
3716
- throw new Error(
3717
- `No such build ${buildId} for application ${appId2}`
3718
- );
3719
- }
3720
- setState((previousState) => ({
3721
- ...previousState,
3722
- appId: appId2,
3723
- build: buildResult
3724
- }));
3725
- }).catch(onError);
3726
- };
3727
- if (id) {
3728
- loadBuild(id);
3729
- } else {
3730
- getLatestBuildId_default({ appId: appId2, userId }).catch(onError).then((buildId) => {
3731
- if (!buildId) {
3732
- setState((previousState) => ({
3733
- ...previousState,
3734
- arbitraryMessageComponent: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: "There are no builds yet" })
3735
- }));
3736
- return;
3737
- }
3738
- return loadBuild(buildId);
3739
- });
3740
- }
3741
- }
3742
- releaseBuild();
3743
- }, [build, id]);
3744
- (0, import_react18.useEffect)(() => {
3745
- if (!build || hasBeenValidatedSuccesfully || arbitraryMessageComponent) {
3746
- return;
3747
- }
3748
- let validationMessage;
3749
- if (build.releasedAt) {
3750
- validationMessage = `It has already been released.`;
3751
- } else if (build.status !== "succeeded") {
3752
- validationMessage = `The build must have completed successfully. Actual build status: ${build.status}`;
3753
- }
3754
- if (validationMessage) {
3755
- setState((previousState) => ({
3756
- ...previousState,
3757
- arbitraryMessageComponent: getValidationErrorMessageDisplay(
3758
- build,
3759
- validationMessage
3760
- ),
3761
- hasBeenValidatedSuccesfully: false
3762
- }));
3763
- } else {
3764
- setState((previousState) => ({
3765
- ...previousState,
3766
- hasBeenValidatedSuccesfully: true
3767
- }));
3768
- }
3769
- }, [arbitraryMessageComponent, build, hasBeenValidatedSuccesfully]);
3770
- (0, import_react18.useEffect)(() => {
3771
- if (!hasBeenValidatedSuccesfully || shouldConfirm && !hasConfirmed || isReleasing || isComplete) {
3772
- return;
3773
- }
3774
- setState((previousState) => ({
3775
- ...previousState,
3776
- isReleasing: true
3777
- }));
3778
- getCallableFirebaseFunction_default("releaseBuild")({
3779
- appId,
3780
- buildId: build.id
3781
- }).then(() => {
3782
- logForCI_default("Released!");
3783
- setState((previousState) => ({
3784
- ...previousState,
3785
- isReleasing: false,
3786
- isComplete: true
3787
- }));
3788
- }).catch((e) => {
3789
- if (["failed-precondition", "not-found"].includes(e.code)) {
3790
- setState((previousState) => ({
3791
- ...previousState,
3792
- arbitraryMessageComponent: getValidationErrorMessageDisplay(
3793
- build,
3794
- e.message
3795
- ),
3796
- isReleasing: false
3797
- }));
3798
- } else {
3799
- onError(new Error("Unexpected internal error while releasing build"));
3800
- }
3801
- });
3802
- }, [
3803
- appId,
3804
- build,
3805
- hasConfirmed,
3806
- hasBeenValidatedSuccesfully,
3807
- id,
3808
- isComplete,
3809
- isReleasing,
3810
- shouldConfirm
3811
- ]);
3812
- (0, import_react18.useEffect)(() => {
3813
- if (isComplete) {
3814
- setTimeout(exit, 10);
3815
- return;
3816
- }
3817
- if (arbitraryMessageComponent) {
3818
- setTimeout(() => exit(new Error("Validation failed")), 10);
3819
- }
3820
- }, [arbitraryMessageComponent, exit, isComplete]);
3821
- if (error) {
3822
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ErrorDisplay_default, { commandUsed, error });
3823
- }
3824
- if (arbitraryMessageComponent) {
3825
- return arbitraryMessageComponent;
3826
- }
3827
- if (hasBeenValidatedSuccesfully && shouldConfirm && !hasConfirmed) {
3828
- const items = [
3829
- {
3830
- label: "Yes",
3831
- value: "yes"
3832
- },
3833
- {
3834
- label: "No",
3835
- value: "no"
3836
- }
3837
- ];
3838
- const onSubmit = (item) => {
3839
- if (item.value === "no") {
3840
- setTimeout(exit, 10);
3841
- return;
3842
- }
3843
- setState((previousState) => ({
3844
- ...previousState,
3845
- hasConfirmed: true
3846
- }));
3847
- };
3848
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { flexDirection: "column", children: [
3849
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { children: [
3850
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Text, { children: [
3851
- "This will release build ",
3852
- build.id,
3853
- " as "
3854
- ] }),
3855
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Text, { bold: true, children: [
3856
- build.appName,
3857
- " v",
3858
- build.appVersion
3859
- ] }),
3860
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: ", are you sure?" })
3861
- ] }),
3862
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3863
- import_ink_select_input2.default,
3864
- {
3865
- indicatorComponent: CustomSelectInputIndicator_default,
3866
- initialIndex: 1,
3867
- itemComponent: CustomSelectInputItem_default,
3868
- items,
3869
- onSelect: onSubmit
3870
- }
3871
- ) }),
3872
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { dimColor: true, children: "Your users will be auto-updated to this version. You can use --force to bypass this confirmation in future" })
3873
- ] });
3874
- }
3875
- if (isReleasing) {
3876
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: "Releasing..." });
3877
- }
3878
- if (isComplete) {
3879
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { bold: true, color: "greenBright", children: "Released!" });
3880
- }
3881
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: "..." });
3882
- };
3883
- ReleaseBuild.propTypes = {
3884
- id: (props, propName, componentName) => {
3885
- if ([props.id, props.shouldReleaseLatest].filter(Boolean).length !== 1) {
3886
- return new Error(
3887
- `Exactly one of 'id' and 'shouldReleaseLatest' must be specified in '${componentName}'`
3888
- );
3889
- }
3890
- const type = typeof props.id;
3891
- if (!["string", "undefined"].includes(type)) {
3892
- return new Error(
3893
- `'id' is a '${type}', not a string, in '${componentName}'.`
3894
- );
3895
- }
3896
- },
3897
- commandUsed: import_prop_types22.default.string.isRequired,
3898
- shouldReleaseLatest: (props, propName, componentName) => {
3899
- if ([props.id, props.shouldReleaseLatest].filter(Boolean).length !== 1) {
3900
- return new Error(
3901
- `Exactly one of 'id' and 'shouldReleaseLatest' must be specified in '${componentName}'`
3902
- );
3903
- }
3904
- const type = typeof props.shouldReleaseLatest;
3905
- if (!["boolean", "undefined"].includes(type)) {
3906
- return new Error(
3907
- `'shouldReleaseLatest' is a '${type}', not a boolean, in '${componentName}'.`
3908
- );
3909
- }
3910
- },
3911
- shouldConfirm: import_prop_types22.default.bool.isRequired,
3912
- configPath: import_prop_types22.default.string
3913
- };
3914
- var ReleaseBuild_default = ReleaseBuild;
3915
-
3916
- // src/components/PickBuildForRelease.tsx
3917
- var import_ink30 = require("ink");
3918
- var import_prop_types24 = __toESM(require("prop-types"));
3919
- var import_react19 = require("react");
3920
-
3921
- // src/components/SelectTable.tsx
3922
- var import_ink29 = require("ink");
3923
- var import_ink_select_input3 = __toESM(require("ink-select-input"));
3924
- var import_prop_types23 = __toESM(require("prop-types"));
3925
- var import_jsx_runtime33 = require("react/jsx-runtime");
3926
- var CustomIndicator = (props) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomSelectInputIndicator_default, { marginTop: 1, ...props });
3650
+ var CustomIndicator = (props) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(CustomSelectInputIndicator, { marginTop: 1, ...props });
3927
3651
  var SelectTable = ({ data, onSelect }) => {
3928
3652
  const keyDetails = getKeyDetails_default(data);
3929
3653
  const getSelectItems = () => {
@@ -3940,7 +3664,7 @@ var SelectTable = ({ data, onSelect }) => {
3940
3664
  index,
3941
3665
  isSelected
3942
3666
  }) => {
3943
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3667
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3944
3668
  TableRow_default,
3945
3669
  {
3946
3670
  data: data[index],
@@ -3950,10 +3674,10 @@ var SelectTable = ({ data, onSelect }) => {
3950
3674
  index
3951
3675
  );
3952
3676
  };
3953
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink29.Box, { flexDirection: "column", children: [
3954
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead_default, { keyDetails, marginLeft: 2 }),
3955
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3956
- import_ink_select_input3.default,
3677
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { flexDirection: "column", children: [
3678
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TableHead_default, { keyDetails, marginLeft: 2 }),
3679
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3680
+ import_ink_select_input2.default,
3957
3681
  {
3958
3682
  indicatorComponent: CustomIndicator,
3959
3683
  itemComponent: ItemComponent,
@@ -3961,7 +3685,7 @@ var SelectTable = ({ data, onSelect }) => {
3961
3685
  onSelect
3962
3686
  }
3963
3687
  ),
3964
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableEnd_default, { keyDetails, marginLeft: 2 })
3688
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TableEnd_default, { keyDetails, marginLeft: 2 })
3965
3689
  ] });
3966
3690
  };
3967
3691
  SelectTable.propTypes = {
@@ -3978,326 +3702,653 @@ SelectTable.propTypes = {
3978
3702
  );
3979
3703
  }
3980
3704
  },
3981
- onSelect: import_prop_types23.default.func
3705
+ onSelect: import_prop_types21.default.func
3982
3706
  };
3983
3707
  var SelectTable_default = SelectTable;
3984
3708
 
3985
- // src/components/PickBuildForRelease.tsx
3986
- var import_jsx_runtime34 = require("react/jsx-runtime");
3987
- var PickBuildForRelease = ({ commandUsed, shouldConfirm, configPath }) => {
3709
+ // src/components/BuildPicker.tsx
3710
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3711
+ function BuildPicker({
3712
+ buildFilter,
3713
+ buildId,
3714
+ children,
3715
+ commandUsed,
3716
+ configPath,
3717
+ loadData = loadPickerData,
3718
+ question = "Which build would you like to test?"
3719
+ }) {
3988
3720
  const exit = useExit_default();
3989
- const [{ error, builds, chosenBuildId, isLoading, user }, setState] = (0, import_react19.useState)({
3990
- error: null,
3991
- builds: null,
3992
- chosenBuildId: null,
3993
- isLoading: true,
3994
- user: null
3995
- });
3996
3721
  const onInput = useInput_default();
3997
- (0, import_react19.useEffect)(() => {
3998
- async function pickBuildForRelease() {
3999
- if (builds) {
4000
- return;
4001
- }
4002
- let config2;
4003
- try {
4004
- config2 = getProjectConfig(configPath).config;
4005
- } catch (e) {
4006
- setState((previousState) => ({ ...previousState, error: e }));
4007
- return;
4008
- }
4009
- const user2 = await findAppUserId_default(config2.id);
4010
- getBuilds({
4011
- addWhereClauses: (query) => query.where("status", "==", "succeeded"),
4012
- appId: config2.id,
4013
- limit: 50,
4014
- userId: user2.id
4015
- }).then((buildsResult) => {
4016
- setState((previousState) => ({
4017
- ...previousState,
4018
- user: user2,
4019
- builds: buildsResult.filter((buildResult) => !buildResult.releasedAt).slice(0, 5),
4020
- isLoading: false
4021
- }));
4022
- }).catch((e) => {
4023
- logForCI_default(e);
4024
- setState((previousState) => ({
4025
- ...previousState,
4026
- error: e,
4027
- isLoading: false
4028
- }));
4029
- });
4030
- }
4031
- pickBuildForRelease();
4032
- }, [builds]);
3722
+ const isRealIdPassed = buildId && buildId !== "latest";
3723
+ const [state, setState] = (0, import_react18.useState)({
3724
+ selectedBuildId: isRealIdPassed ? buildId : null,
3725
+ state: isRealIdPassed ? "selected" : "loading"
3726
+ });
3727
+ (0, import_react18.useEffect)(() => {
3728
+ loadData({
3729
+ buildFilter,
3730
+ buildId,
3731
+ configPath,
3732
+ state: state.state,
3733
+ updateState
3734
+ });
3735
+ }, []);
4033
3736
  onInput((input, key) => {
4034
- if (!builds || !builds.length || chosenBuildId) {
4035
- return;
4036
- }
4037
- if (key.escape) {
3737
+ if (key.escape && ["show-builds", "loading"].includes(state.state)) {
4038
3738
  exit();
4039
3739
  }
4040
3740
  });
4041
- if (error) {
4042
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ErrorDisplay_default, { commandUsed, error });
3741
+ function updateState(changes) {
3742
+ setState((previousState) => ({ ...previousState, ...changes }));
4043
3743
  }
4044
- if (isLoading) {
4045
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(LoadingText_default, {});
3744
+ function onSelect(item) {
3745
+ updateState({ selectedBuildId: item.value.ID, state: "selected" });
4046
3746
  }
4047
- if (chosenBuildId) {
4048
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
4049
- ReleaseBuild_default,
4050
- {
4051
- commandUsed,
4052
- id: chosenBuildId,
4053
- shouldConfirm
3747
+ switch (state.state) {
3748
+ case "error":
3749
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ErrorDisplay_default, { commandUsed, error: state.error });
3750
+ case "loading":
3751
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(LoadingText_default, {});
3752
+ case "no-builds":
3753
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink29.Box, { children: [
3754
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink29.Text, { children: "No eligible builds found " }),
3755
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink29.Text, { dimColor: true, children: "(candidates for smoke-test must be built with @todesktop/runtime@1.2.1 or later)" })
3756
+ ] });
3757
+ case "selected":
3758
+ return children(state.selectedBuildId);
3759
+ case "show-builds":
3760
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
3761
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink29.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink29.Text, { children: question }) }),
3762
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(SelectTable_default, { data: state.builds, onSelect }),
3763
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_ink29.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink29.Text, { dimColor: true, children: [
3764
+ "Showing the latest ",
3765
+ state.builds.length,
3766
+ " unreleased successful builds"
3767
+ ] }) })
3768
+ ] });
3769
+ default:
3770
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3771
+ ErrorDisplay_default,
3772
+ {
3773
+ commandUsed,
3774
+ error: new Error(`Unknown state ${state.state}`)
3775
+ }
3776
+ );
3777
+ }
3778
+ }
3779
+ async function loadPickerData({
3780
+ buildFilter,
3781
+ buildId,
3782
+ configPath,
3783
+ state,
3784
+ updateState
3785
+ }) {
3786
+ if (state === "selected") {
3787
+ return;
3788
+ }
3789
+ try {
3790
+ if (buildId === "latest") {
3791
+ const latestBuildId = await getLatestBuild({ configPath });
3792
+ if (latestBuildId) {
3793
+ updateState({ state: "selected", selectedBuildId: latestBuildId });
3794
+ } else {
3795
+ updateState({ state: "no-builds" });
4054
3796
  }
4055
- );
3797
+ } else {
3798
+ const builds = await getBuildItems({ buildFilter, configPath });
3799
+ updateState({
3800
+ builds,
3801
+ state: builds.length > 0 ? "show-builds" : "no-builds"
3802
+ });
3803
+ }
3804
+ } catch (error) {
3805
+ updateState({ error, state: "error" });
4056
3806
  }
4057
- if (builds.length) {
4058
- const data = builds.map((build) => ({
4059
- ID: build.id,
4060
- Version: build.appVersion || "unknown",
4061
- "Creation date": getRelativeDateFromDateString_default(build.createdAt),
4062
- Owner: user ? user.label : "unknown"
4063
- }));
4064
- const onSelect = (item) => setState((previousState) => ({
4065
- ...previousState,
4066
- chosenBuildId: item.value.ID
4067
- }));
4068
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
4069
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { children: "Which build would you like to release?" }) }),
4070
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SelectTable_default, { data, onSelect }),
4071
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ink30.Text, { dimColor: true, children: [
4072
- "Showing the latest ",
4073
- builds.length,
4074
- " unreleased successful builds"
4075
- ] }) })
4076
- ] });
4077
- } else {
4078
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ink30.Box, { children: [
4079
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { children: "No eligible builds found " }),
4080
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { dimColor: true, children: "(i.e. unreleased and successful)" })
4081
- ] });
3807
+ }
3808
+ async function getLatestBuild({
3809
+ configPath
3810
+ }) {
3811
+ const { id: appId } = getProjectConfig(configPath).config;
3812
+ const { id: userId } = await findAppUserId_default(appId);
3813
+ return getLatestBuildId_default({ appId, userId });
3814
+ }
3815
+ async function getBuildItems({
3816
+ buildFilter = () => true,
3817
+ configPath
3818
+ }) {
3819
+ const { id: appId } = getProjectConfig(configPath).config;
3820
+ const { id: userId, label: userName } = await findAppUserId_default(appId);
3821
+ const rawBuilds = await getBuilds({
3822
+ addWhereClauses: (query) => query.where("status", "==", "succeeded"),
3823
+ appId,
3824
+ limit: 50,
3825
+ userId
3826
+ });
3827
+ return rawBuilds.filter(buildFilter).slice(0, 5).map((build) => ({
3828
+ ID: build.id,
3829
+ Version: build.appVersion || "unknown",
3830
+ "Creation date": getRelativeDateFromDateString_default(build.createdAt),
3831
+ Owner: userName || "unknown"
3832
+ }));
3833
+ }
3834
+
3835
+ // src/commands/release/components/ReleaseBuild.tsx
3836
+ var import_ink31 = require("ink");
3837
+ var import_react19 = require("react");
3838
+
3839
+ // src/components/BuildError.tsx
3840
+ var import_ink30 = require("ink");
3841
+ var import_ink_link4 = __toESM(require("ink-link"));
3842
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3843
+ function BuildError({
3844
+ build,
3845
+ description = "Can't release",
3846
+ message: message2
3847
+ }) {
3848
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ink30.Box, { flexDirection: "column", children: [
3849
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ink30.Text, { bold: true, color: "red", children: [
3850
+ description,
3851
+ " ",
3852
+ build.appName,
3853
+ " v",
3854
+ build.appVersion
3855
+ ] }),
3856
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { children: message2 }) }),
3857
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { bold: true, children: "See web UI for more information: " }),
3858
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink_link4.default, { fallback: false, url: build.url, children: build.url }) })
3859
+ ] });
3860
+ }
3861
+
3862
+ // src/utilities/getBuildById.ts
3863
+ async function getBuildById({
3864
+ appId,
3865
+ buildId,
3866
+ userId
3867
+ }) {
3868
+ logger_default.debug({ appId, buildId }, "getBuildById");
3869
+ const snapshot = await firestore_default.doc(`users/${userId}/applications/${appId}/builds/${buildId}`).get();
3870
+ if (!snapshot.exists) {
3871
+ return null;
4082
3872
  }
4083
- };
4084
- PickBuildForRelease.propTypes = {
4085
- commandUsed: import_prop_types24.default.string.isRequired,
4086
- shouldConfirm: import_prop_types24.default.bool.isRequired,
4087
- configPath: import_prop_types24.default.string
4088
- };
4089
- var PickBuildForRelease_default = PickBuildForRelease;
3873
+ return snapshot.data();
3874
+ }
3875
+
3876
+ // src/utilities/getBuildAttributes.ts
3877
+ async function getBuildAttributes({
3878
+ buildId,
3879
+ configPath
3880
+ }) {
3881
+ const { id: appId, nodeVersion } = getProjectConfig(configPath).config;
3882
+ const userId = await fetchUserIdByAppId(appId);
3883
+ const build = await fetchBuild({ appId, buildId, userId });
3884
+ return { appId, build, buildId, nodeVersion, userId };
3885
+ }
3886
+ async function fetchBuild({
3887
+ appId,
3888
+ buildId,
3889
+ userId
3890
+ }) {
3891
+ const build = await getBuildById({ appId, buildId, userId });
3892
+ if (!build) {
3893
+ throw new Error(`No such build ${buildId} for application ${appId}`);
3894
+ }
3895
+ return build;
3896
+ }
3897
+ async function fetchUserIdByAppId(appId) {
3898
+ try {
3899
+ const { id: userId } = await findAppUserId_default(appId);
3900
+ return userId;
3901
+ } catch (e) {
3902
+ throw new Error(`Can't fetch user for app ${appId}, ${e.message}`);
3903
+ }
3904
+ }
4090
3905
 
4091
- // src/commands/ReleaseCommand.tsx
3906
+ // src/commands/release/components/ReleaseBuild.tsx
4092
3907
  var import_jsx_runtime35 = require("react/jsx-runtime");
4093
- var ReleaseCommand = ({
3908
+ function ReleaseBuild({
3909
+ commandUsed,
4094
3910
  id,
4095
- force,
4096
- shouldReleaseLatest,
4097
3911
  configPath
4098
- }) => {
4099
- checkIfReactIsUsable_default();
4100
- useAnalyticsCommand("release", {
4101
- id,
4102
- force,
4103
- shouldReleaseLatest,
4104
- config: configPath
3912
+ }) {
3913
+ const exit = useExit_default();
3914
+ const [
3915
+ {
3916
+ appId,
3917
+ arbitraryMessageComponent,
3918
+ build,
3919
+ error,
3920
+ hasBeenValidatedSuccessfully,
3921
+ isComplete,
3922
+ isReleasing
3923
+ },
3924
+ setState
3925
+ ] = (0, import_react19.useState)({
3926
+ appId: null,
3927
+ build: null,
3928
+ error: null,
3929
+ hasBeenValidatedSuccessfully: false,
3930
+ isComplete: false,
3931
+ isReleasing: false,
3932
+ arbitraryMessageComponent: null
4105
3933
  });
4106
- if (id && id.startsWith(".")) {
4107
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
4108
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_ink31.Box, { children: [
4109
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { bold: true, color: "red", children: "todesktop release <project-path>" }),
4110
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { children: " is no longer supported. Run this instead:" })
4111
- ] }),
4112
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { bold: true, color: "greenBright", children: "todesktop build && todesktop release --latest --force" })
4113
- ] });
4114
- }
4115
- const getContents = () => {
4116
- if (id) {
4117
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4118
- ReleaseBuild_default,
4119
- {
4120
- configPath,
4121
- commandUsed: "todesktop release <id>",
4122
- id,
4123
- shouldConfirm: !force
4124
- }
4125
- );
4126
- } else if (shouldReleaseLatest) {
4127
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4128
- ReleaseBuild_default,
4129
- {
4130
- configPath,
4131
- commandUsed: "todesktop release --latest",
4132
- shouldReleaseLatest: true,
4133
- shouldConfirm: !force
4134
- }
4135
- );
3934
+ const onError = (e) => {
3935
+ const error2 = e.response ? e.response.data : e;
3936
+ logForCI_default(error2);
3937
+ setState((prevState) => ({
3938
+ ...prevState,
3939
+ error: error2
3940
+ }));
3941
+ };
3942
+ (0, import_react19.useEffect)(() => {
3943
+ if (!build) {
3944
+ getBuildAttributes({ buildId: id, configPath }).then(({ appId: appId2, build: build2 }) => {
3945
+ setState((previousState) => ({ ...previousState, appId: appId2, build: build2 }));
3946
+ }).catch(onError);
3947
+ }
3948
+ }, [build, configPath, id]);
3949
+ (0, import_react19.useEffect)(() => {
3950
+ if (!build || hasBeenValidatedSuccessfully || arbitraryMessageComponent) {
3951
+ return;
3952
+ }
3953
+ let validationMessage;
3954
+ if (build.releasedAt) {
3955
+ validationMessage = `It has already been released.`;
3956
+ } else if (build.status !== "succeeded") {
3957
+ validationMessage = `The build must have completed successfully. Actual build status: ${build.status}`;
3958
+ }
3959
+ if (validationMessage) {
3960
+ setState((previousState) => ({
3961
+ ...previousState,
3962
+ arbitraryMessageComponent: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(BuildError, { build, message: validationMessage }),
3963
+ hasBeenValidatedSuccessfully: false
3964
+ }));
4136
3965
  } else {
4137
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
4138
- PickBuildForRelease_default,
4139
- {
4140
- configPath,
4141
- commandUsed: "todesktop builds",
4142
- shouldConfirm: !force
4143
- }
4144
- );
3966
+ setState((previousState) => ({
3967
+ ...previousState,
3968
+ hasBeenValidatedSuccessfully: true
3969
+ }));
4145
3970
  }
4146
- };
4147
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(LoginHOC_default, { children: getContents() }) });
3971
+ }, [arbitraryMessageComponent, build, hasBeenValidatedSuccessfully]);
3972
+ (0, import_react19.useEffect)(() => {
3973
+ if (!hasBeenValidatedSuccessfully || isReleasing || isComplete) {
3974
+ return;
3975
+ }
3976
+ setState((previousState) => ({
3977
+ ...previousState,
3978
+ isReleasing: true
3979
+ }));
3980
+ getCallableFirebaseFunction_default("releaseBuild")({
3981
+ appId,
3982
+ buildId: build.id
3983
+ }).then(() => {
3984
+ logForCI_default("Released!");
3985
+ setState((previousState) => ({
3986
+ ...previousState,
3987
+ isReleasing: false,
3988
+ isComplete: true
3989
+ }));
3990
+ }).catch((e) => {
3991
+ if (["failed-precondition", "not-found"].includes(e.code)) {
3992
+ setState((previousState) => ({
3993
+ ...previousState,
3994
+ arbitraryMessageComponent: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3995
+ BuildError,
3996
+ {
3997
+ build,
3998
+ message: e instanceof Error ? e.message : JSON.stringify(e)
3999
+ }
4000
+ ),
4001
+ isReleasing: false
4002
+ }));
4003
+ } else {
4004
+ onError(new Error("Unexpected internal error while releasing build"));
4005
+ }
4006
+ });
4007
+ }, [appId, build, hasBeenValidatedSuccessfully, id, isComplete, isReleasing]);
4008
+ (0, import_react19.useEffect)(() => {
4009
+ if (isComplete) {
4010
+ setTimeout(exit, 10);
4011
+ return;
4012
+ }
4013
+ if (arbitraryMessageComponent) {
4014
+ setTimeout(() => exit(new Error("Validation failed")), 10);
4015
+ }
4016
+ }, [arbitraryMessageComponent, exit, isComplete]);
4017
+ if (error) {
4018
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ErrorDisplay_default, { commandUsed, error });
4019
+ }
4020
+ if (arbitraryMessageComponent) {
4021
+ return arbitraryMessageComponent;
4022
+ }
4023
+ if (isReleasing) {
4024
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { children: "Releasing..." });
4025
+ }
4026
+ if (isComplete) {
4027
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { bold: true, color: "greenBright", children: "Released!" });
4028
+ }
4029
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { children: "..." });
4030
+ }
4031
+
4032
+ // src/commands/release/components/ReleaseConfirmation.tsx
4033
+ var import_ink33 = require("ink");
4034
+ var import_react20 = require("react");
4035
+
4036
+ // src/commands/smoke-test/utilities/build.ts
4037
+ var import_semver = __toESM(require("semver"));
4038
+
4039
+ // src/commands/smoke-test/utilities/SmokeError.ts
4040
+ var SmokeError = class extends Error {
4041
+ constructor(message2, { cause, type = "error" } = {}) {
4042
+ super(message2, { cause });
4043
+ this.type = type;
4044
+ }
4148
4045
  };
4149
- var ReleaseCommand_default = ReleaseCommand;
4150
4046
 
4151
- // src/commands/smoke-test/SmokeTestCommand.tsx
4152
- var import_react22 = require("react");
4047
+ // src/commands/smoke-test/utilities/build.ts
4048
+ var MIN_RUNTIME_VERSION = "1.2.1-1";
4049
+ function isBuildTestable(build) {
4050
+ try {
4051
+ validateBuild(build);
4052
+ return true;
4053
+ } catch (e) {
4054
+ return false;
4055
+ }
4056
+ }
4057
+ function isTestRunning(build) {
4058
+ if (!build.smokeTest) {
4059
+ return false;
4060
+ }
4061
+ const { isFinished } = makeProgress(build);
4062
+ return !isFinished;
4063
+ }
4064
+ function makeProgress(build) {
4065
+ var _a, _b, _c, _d, _e, _f, _g;
4066
+ const defaultProgress = {
4067
+ message: "Starting",
4068
+ progress: 0,
4069
+ state: "progress",
4070
+ shouldSkip: false
4071
+ };
4072
+ const linux = {
4073
+ ...defaultProgress,
4074
+ ...(_a = build.smokeTest) == null ? void 0 : _a.linux,
4075
+ shouldSkip: ((_b = build.linux) == null ? void 0 : _b.shouldSkip) || false
4076
+ };
4077
+ const mac = {
4078
+ ...defaultProgress,
4079
+ ...(_c = build.smokeTest) == null ? void 0 : _c.mac,
4080
+ shouldSkip: ((_d = build.mac) == null ? void 0 : _d.shouldSkip) || false
4081
+ };
4082
+ const windows = {
4083
+ ...defaultProgress,
4084
+ ...(_e = build.smokeTest) == null ? void 0 : _e.windows,
4085
+ shouldSkip: ((_f = build.windows) == null ? void 0 : _f.shouldSkip) || false
4086
+ };
4087
+ const platforms = [linux, mac, windows].filter(
4088
+ (p) => !p.shouldSkip && p.state !== "skipped"
4089
+ );
4090
+ const isCanceled = Boolean((_g = build.smokeTest) == null ? void 0 : _g.isCanceled);
4091
+ const isFinished = isCanceled || platforms.every((p) => p.state !== "progress");
4092
+ let totalState = "progress";
4093
+ if (isCanceled) {
4094
+ totalState = "canceled";
4095
+ } else if (platforms.every((p) => p.state === "done")) {
4096
+ totalState = "done";
4097
+ } else if (isFinished && platforms.some((p) => p.state === "error")) {
4098
+ totalState = "error";
4099
+ }
4100
+ return {
4101
+ isFinished,
4102
+ linux,
4103
+ mac,
4104
+ windows,
4105
+ total: {
4106
+ error: platforms.filter((p) => p.state === "error").map((p) => p.message).join("\n\n"),
4107
+ state: totalState
4108
+ }
4109
+ };
4110
+ }
4111
+ function validateBuild(build) {
4112
+ if (build.status !== "succeeded") {
4113
+ throw new SmokeError(
4114
+ `The build must be completed successfully. Actual build status: ${build.status}`
4115
+ );
4116
+ }
4117
+ if (!build.todesktopRuntimeVersionSpecified) {
4118
+ throw new SmokeError(
4119
+ "The build has no todesktopRuntimeVersionSpecified set. Please make sure @todesktop/runtime is installed as a dependency and make a new build"
4120
+ );
4121
+ }
4122
+ if (!isRuntimeVerRangeAllowed(build.todesktopRuntimeVersionSpecified)) {
4123
+ throw new SmokeError(
4124
+ `The build should have @todesktop/shared@${MIN_RUNTIME_VERSION} installed at least`
4125
+ );
4126
+ }
4127
+ }
4128
+ function isRuntimeVerRangeAllowed(runtimeVerRange) {
4129
+ const minRuntimeVersionForApp = import_semver.default.minVersion(runtimeVerRange, {
4130
+ loose: true
4131
+ });
4132
+ return import_semver.default.gte(minRuntimeVersionForApp, MIN_RUNTIME_VERSION, {
4133
+ loose: true
4134
+ });
4135
+ }
4153
4136
 
4154
- // src/commands/smoke-test/components/BuildPicker.tsx
4137
+ // src/commands/release/components/YesNoConfirmation.tsx
4155
4138
  var import_ink32 = require("ink");
4156
- var import_react20 = require("react");
4139
+ var import_ink_select_input3 = __toESM(require("ink-select-input"));
4157
4140
  var import_jsx_runtime36 = require("react/jsx-runtime");
4158
- function BuildPicker({
4159
- buildFilter,
4141
+ function YesNoConfirmation({
4142
+ onYes,
4143
+ title,
4144
+ footer = "Your users will be auto-updated to this version. You can use --force to bypass this confirmation in future"
4145
+ }) {
4146
+ const exit = useExit_default();
4147
+ const items = [
4148
+ { label: "Yes", value: "yes" },
4149
+ { label: "No", value: "no" }
4150
+ ];
4151
+ function onSelect(item) {
4152
+ if (item.value === "yes") {
4153
+ onYes();
4154
+ } else if (item.value === "no") {
4155
+ setTimeout(() => exit(), 10);
4156
+ }
4157
+ }
4158
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_ink32.Box, { flexDirection: "column", children: [
4159
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Box, { children: typeof title === "string" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { children: title }) : title }),
4160
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4161
+ import_ink_select_input3.default,
4162
+ {
4163
+ indicatorComponent: CustomSelectInputIndicator,
4164
+ initialIndex: 1,
4165
+ itemComponent: CustomSelectInputItem_default,
4166
+ items,
4167
+ onSelect
4168
+ }
4169
+ ) }),
4170
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { dimColor: true, children: footer })
4171
+ ] });
4172
+ }
4173
+
4174
+ // src/commands/release/components/ReleaseConfirmation.tsx
4175
+ var import_jsx_runtime37 = require("react/jsx-runtime");
4176
+ function ReleaseConfirmation({
4160
4177
  buildId,
4161
4178
  children,
4162
- commandUsed,
4163
4179
  configPath,
4164
- question = "Which build would you like to test?"
4180
+ disabled = false,
4181
+ loadBuild = getBuildAttributes
4165
4182
  }) {
4166
- const exit = useExit_default();
4167
- const onInput = useInput_default();
4168
- const isRealIdPassed = buildId && buildId !== "latest";
4169
4183
  const [state, setState] = (0, import_react20.useState)({
4170
- selectedBuildId: isRealIdPassed ? buildId : null,
4171
- state: isRealIdPassed ? "selected" : "loading"
4184
+ state: disabled ? "bypass" : "loading"
4172
4185
  });
4173
4186
  (0, import_react20.useEffect)(() => {
4174
- loadPickerData({
4175
- buildFilter,
4187
+ confirmationWorkflow({
4176
4188
  buildId,
4177
- configPath,
4178
- state: state.state,
4179
- updateState
4180
- });
4181
- }, []);
4182
- onInput((input, key) => {
4183
- if (key.escape && ["show-builds", "loading"].includes(state.state)) {
4184
- exit();
4185
- }
4186
- });
4189
+ configPath,
4190
+ loadBuild,
4191
+ setState,
4192
+ state
4193
+ }).catch((error) => {
4194
+ setState({ state: "error", error });
4195
+ });
4196
+ }, []);
4187
4197
  function updateState(changes) {
4188
4198
  setState((previousState) => ({ ...previousState, ...changes }));
4189
4199
  }
4190
- function onSelect(item) {
4191
- updateState({ selectedBuildId: item.value.ID, state: "selected" });
4192
- }
4193
4200
  switch (state.state) {
4194
- case "error":
4195
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ErrorDisplay_default, { commandUsed, error: state.error });
4196
- case "loading":
4197
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(LoadingText_default, {});
4198
- case "no-builds":
4199
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_ink32.Box, { children: [
4200
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { children: "No eligible builds found " }),
4201
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { dimColor: true, children: "(candidates for smoke-test must be built with @todesktop/runtime@1.2.1 or later)" })
4202
- ] });
4203
- case "selected":
4204
- return children(state.selectedBuildId);
4205
- case "show-builds":
4206
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
4207
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { children: question }) }),
4208
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SelectTable_default, { data: state.builds, onSelect }),
4209
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_ink32.Text, { dimColor: true, children: [
4210
- "Showing the latest ",
4211
- state.builds.length,
4212
- " unreleased successful builds"
4213
- ] }) })
4214
- ] });
4215
- default:
4216
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
4217
- ErrorDisplay_default,
4201
+ case "bypass":
4202
+ return children;
4203
+ case "confirm-release":
4204
+ if (!state.build) {
4205
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ErrorDisplay_default, { error: new Error("state.build is empty") });
4206
+ }
4207
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4208
+ YesNoConfirmation,
4218
4209
  {
4219
- commandUsed,
4220
- error: new Error(`Unknown state ${state.state}`)
4210
+ title: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
4211
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ink33.Text, { children: [
4212
+ "This will release build ",
4213
+ state.build.id,
4214
+ " as "
4215
+ ] }),
4216
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ink33.Text, { bold: true, children: [
4217
+ state.build.appName,
4218
+ " v",
4219
+ state.build.appVersion
4220
+ ] }),
4221
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ink33.Text, { children: ", are you sure?" })
4222
+ ] }),
4223
+ onYes: () => updateState({ state: "bypass" })
4221
4224
  }
4222
4225
  );
4226
+ case "confirm-test":
4227
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
4228
+ YesNoConfirmation,
4229
+ {
4230
+ title: state.testConfirmationText,
4231
+ onYes: () => updateState({ state: "confirm-release" })
4232
+ }
4233
+ );
4234
+ case "error":
4235
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ErrorDisplay_default, { error: state.error });
4236
+ case "loading":
4237
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LoadingText_default, {});
4238
+ default:
4239
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ErrorDisplay_default, { error: new Error(`Unknown state ${state.state}`) });
4223
4240
  }
4224
4241
  }
4225
- async function loadPickerData({
4226
- buildFilter,
4242
+ async function confirmationWorkflow({
4227
4243
  buildId,
4228
4244
  configPath,
4229
- state,
4230
- updateState
4245
+ loadBuild,
4246
+ setState,
4247
+ state
4231
4248
  }) {
4232
- if (state === "selected") {
4249
+ if (state.state === "bypass") {
4233
4250
  return;
4234
4251
  }
4235
- try {
4236
- if (buildId === "latest") {
4237
- const latestBuildId = await getLatestBuild({ configPath });
4238
- if (latestBuildId) {
4239
- updateState({ state: "selected", selectedBuildId: latestBuildId });
4240
- } else {
4241
- updateState({ state: "no-builds" });
4242
- }
4243
- } else {
4244
- const builds = await getBuildItems({ buildFilter, configPath });
4245
- updateState({
4246
- builds,
4247
- state: builds.length > 0 ? "show-builds" : "no-builds"
4248
- });
4249
- }
4250
- } catch (error) {
4251
- updateState({ error, state: "error" });
4252
- }
4252
+ const { build } = await loadBuild({ buildId, configPath });
4253
+ const testConfirmationText = getTestConfirmation(build);
4254
+ setState({
4255
+ build,
4256
+ testConfirmationText,
4257
+ state: testConfirmationText ? "confirm-test" : "confirm-release"
4258
+ });
4253
4259
  }
4254
- async function getLatestBuild({
4255
- configPath
4256
- }) {
4257
- const { id: appId } = getProjectConfig(configPath).config;
4258
- const { id: userId } = await findAppUserId_default(appId);
4259
- return getLatestBuildId_default({ appId, userId });
4260
+ function getTestConfirmation(build) {
4261
+ const continueText = "Are you sure you want to release?";
4262
+ if (!build.todesktopRuntimeVersionSpecified || !isBuildTestable(build)) {
4263
+ return "";
4264
+ }
4265
+ if (!build.smokeTest) {
4266
+ return `Smoke test hasn't been run for this build. ${continueText}`;
4267
+ }
4268
+ const { total } = makeProgress(build);
4269
+ switch (total.state) {
4270
+ case "error":
4271
+ return `Smoke test failed for this build. ${continueText}`;
4272
+ case "canceled":
4273
+ return `Smoke test was canceled for this build. ${continueText}`;
4274
+ case "progress":
4275
+ return `Smoke test is currently running for this build. ${continueText}`;
4276
+ default:
4277
+ return "";
4278
+ }
4260
4279
  }
4261
- async function getBuildItems({
4262
- buildFilter = () => true,
4263
- configPath
4280
+
4281
+ // src/commands/release/ReleaseCommand.tsx
4282
+ var import_jsx_runtime38 = require("react/jsx-runtime");
4283
+ function ReleaseCommand({
4284
+ buildId,
4285
+ configPath,
4286
+ shouldConfirm
4264
4287
  }) {
4265
- const { id: appId } = getProjectConfig(configPath).config;
4266
- const { id: userId, label: userName } = await findAppUserId_default(appId);
4267
- const rawBuilds = await getBuilds({
4268
- addWhereClauses: (query) => query.where("status", "==", "succeeded"),
4269
- appId,
4270
- limit: 50,
4271
- userId
4288
+ checkIfReactIsUsable_default();
4289
+ useAnalyticsCommand("release", {
4290
+ buildId,
4291
+ shouldConfirm,
4292
+ config: configPath
4272
4293
  });
4273
- return rawBuilds.filter(buildFilter).slice(0, 5).map((build) => ({
4274
- ID: build.id,
4275
- Version: build.appVersion || "unknown",
4276
- "Creation date": getRelativeDateFromDateString_default(build.createdAt),
4277
- Owner: userName || "unknown"
4278
- }));
4294
+ let command = "todesktop release";
4295
+ if (buildId) {
4296
+ command += " " + (buildId === "latest" ? "--latest" : "<id>");
4297
+ }
4298
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(LoginHOC_default, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4299
+ BuildPicker,
4300
+ {
4301
+ buildFilter: isBuildReleasable,
4302
+ buildId,
4303
+ commandUsed: command,
4304
+ configPath,
4305
+ question: "Which build would you like to release?",
4306
+ children: (id) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4307
+ ReleaseConfirmation,
4308
+ {
4309
+ buildId: id,
4310
+ configPath,
4311
+ disabled: !shouldConfirm,
4312
+ children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
4313
+ ReleaseBuild,
4314
+ {
4315
+ commandUsed: command,
4316
+ configPath,
4317
+ id
4318
+ }
4319
+ )
4320
+ }
4321
+ )
4322
+ }
4323
+ ) }) });
4279
4324
  }
4325
+ function isBuildReleasable(build) {
4326
+ return !build.releasedAt;
4327
+ }
4328
+
4329
+ // src/commands/smoke-test/SmokeTestCommand.tsx
4330
+ var import_react22 = require("react");
4280
4331
 
4281
4332
  // src/commands/smoke-test/components/Cancellation.tsx
4282
- var import_ink33 = require("ink");
4333
+ var import_ink34 = require("ink");
4283
4334
  var import_react21 = require("react");
4284
- var import_jsx_runtime37 = require("react/jsx-runtime");
4335
+ var import_jsx_runtime39 = require("react/jsx-runtime");
4285
4336
  function Cancellation({
4286
4337
  children,
4287
4338
  disabled = false,
4288
4339
  exitWhenCanceled = true,
4289
4340
  onCancel,
4290
- renderCanceling = () => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LoadingText_default, { text: `Canceling ${subject}` }),
4291
- renderCanceled = () => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ink33.Text, { children: [
4341
+ renderCanceling = () => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LoadingText_default, { text: `Canceling ${subject}` }),
4342
+ renderCanceled = () => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_ink34.Text, { children: [
4292
4343
  upperCaseFirstChar(subject),
4293
4344
  " canceled."
4294
4345
  ] }),
4295
- renderCancelText = () => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_ink33.Text, { color: "gray", children: [
4296
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ink33.Text, { bold: true, children: "[esc]:" }),
4346
+ renderCancelText = () => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_ink34.Text, { color: "gray", children: [
4347
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink34.Text, { bold: true, children: "[esc]:" }),
4297
4348
  " cancel ",
4298
4349
  subject
4299
4350
  ] }),
4300
- renderError = (e) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ErrorDisplay_default, { error: e }),
4351
+ renderError = (e) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ErrorDisplay_default, { error: e }),
4301
4352
  subject
4302
4353
  }) {
4303
4354
  const [state, setState] = (0, import_react21.useState)("normal");
@@ -4333,9 +4384,9 @@ function Cancellation({
4333
4384
  case "error":
4334
4385
  return renderError(error);
4335
4386
  default:
4336
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
4387
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
4337
4388
  children,
4338
- !disabled && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_ink33.Box, { children: renderCancelText() })
4389
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink34.Box, { children: renderCancelText() })
4339
4390
  ] });
4340
4391
  }
4341
4392
  }
@@ -4346,30 +4397,9 @@ function upperCaseFirstChar(str) {
4346
4397
  // src/commands/smoke-test/components/SmokeTestView.tsx
4347
4398
  var import_ink36 = require("ink");
4348
4399
 
4349
- // src/commands/smoke-test/components/BuildError.tsx
4350
- var import_ink34 = require("ink");
4351
- var import_ink_link5 = __toESM(require("ink-link"));
4352
- var import_jsx_runtime38 = require("react/jsx-runtime");
4353
- function BuildError({
4354
- build,
4355
- message: message2
4356
- }) {
4357
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_ink34.Box, { flexDirection: "column", children: [
4358
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_ink34.Text, { bold: true, color: "red", children: [
4359
- "Can't finish smoke test ",
4360
- build.appName,
4361
- " v",
4362
- build.appVersion
4363
- ] }),
4364
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ink34.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ink34.Text, { children: message2 }) }),
4365
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ink34.Text, { bold: true, children: "See web UI for more information: " }),
4366
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ink34.Text, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_ink_link5.default, { fallback: false, url: build.url, children: build.url }) })
4367
- ] });
4368
- }
4369
-
4370
4400
  // src/commands/smoke-test/components/ProgressBar.tsx
4371
4401
  var import_ink35 = require("ink");
4372
- var import_jsx_runtime39 = require("react/jsx-runtime");
4402
+ var import_jsx_runtime40 = require("react/jsx-runtime");
4373
4403
  function ProgressBar2({
4374
4404
  color = "white",
4375
4405
  label,
@@ -4380,28 +4410,28 @@ function ProgressBar2({
4380
4410
  }) {
4381
4411
  const percentage = progress > 0 ? Math.round(progress).toString().padStart(2, "0") + "%" : "";
4382
4412
  const displayedText = (text || "").replace(/(?:\r\n|\r|\n)\s*/g, "\u21B5 ").replace(/(.{63}).+/, "$1\u2026");
4383
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_ink35.Box, { marginBottom, children: [
4384
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink35.Box, { width: labelWidth, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_ink35.Text, { children: [
4413
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_ink35.Box, { marginBottom, children: [
4414
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ink35.Box, { width: labelWidth, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_ink35.Text, { children: [
4385
4415
  label,
4386
4416
  ":"
4387
4417
  ] }) }),
4388
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink35.Box, { width: 6, justifyContent: "flex-end", marginRight: 1, children: Boolean(percentage) && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink35.Text, { backgroundColor: color, color: "black", children: ` ${percentage} ` }) }),
4389
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink35.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_ink35.Text, { children: displayedText }) })
4418
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ink35.Box, { width: 6, justifyContent: "flex-end", marginRight: 1, children: Boolean(percentage) && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ink35.Text, { backgroundColor: color, color: "black", children: ` ${percentage} ` }) }),
4419
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ink35.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_ink35.Text, { children: displayedText }) })
4390
4420
  ] });
4391
4421
  }
4392
4422
 
4393
4423
  // src/commands/smoke-test/components/TestProgress.tsx
4394
- var import_jsx_runtime40 = require("react/jsx-runtime");
4424
+ var import_jsx_runtime41 = require("react/jsx-runtime");
4395
4425
  function TestProgress({
4396
4426
  progress
4397
4427
  }) {
4398
4428
  if (!progress) {
4399
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(LoadingText_default, { text: "Loading test stats" });
4429
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(LoadingText_default, { text: "Loading test stats" });
4400
4430
  }
4401
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
4402
- !progress.windows.shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(OsProgress, { os: "Windows", progress: progress.windows }),
4403
- !progress.mac.shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(OsProgress, { os: "macOS", progress: progress.mac }),
4404
- !progress.linux.shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(OsProgress, { os: "Linux", progress: progress.linux })
4431
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
4432
+ !progress.windows.shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(OsProgress, { os: "Windows", progress: progress.windows }),
4433
+ !progress.mac.shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(OsProgress, { os: "macOS", progress: progress.mac }),
4434
+ !progress.linux.shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(OsProgress, { os: "Linux", progress: progress.linux })
4405
4435
  ] });
4406
4436
  }
4407
4437
  function OsProgress({
@@ -4415,7 +4445,7 @@ function OsProgress({
4415
4445
  skipped: "yellow"
4416
4446
  };
4417
4447
  const text = progress.message + (progress.state === "progress" ? "..." : "");
4418
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4448
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4419
4449
  ProgressBar2,
4420
4450
  {
4421
4451
  color: colors[progress.state],
@@ -4427,7 +4457,7 @@ function OsProgress({
4427
4457
  }
4428
4458
 
4429
4459
  // src/commands/smoke-test/components/SmokeTestView.tsx
4430
- var import_jsx_runtime41 = require("react/jsx-runtime");
4460
+ var import_jsx_runtime42 = require("react/jsx-runtime");
4431
4461
  function SmokeTestView({
4432
4462
  commandUsed = "",
4433
4463
  state
@@ -4435,14 +4465,21 @@ function SmokeTestView({
4435
4465
  var _a, _b, _c, _d;
4436
4466
  switch (state.state) {
4437
4467
  case "build-error": {
4438
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(BuildError, { build: state.build, message: (_a = state.error) == null ? void 0 : _a.message });
4468
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4469
+ BuildError,
4470
+ {
4471
+ build: state.build,
4472
+ description: "Can't finish smoke test",
4473
+ message: (_a = state.error) == null ? void 0 : _a.message
4474
+ }
4475
+ );
4439
4476
  }
4440
4477
  case "canceled":
4441
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ink36.Text, { children: "Smoke test canceled." });
4478
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ink36.Text, { children: "Smoke test canceled." });
4442
4479
  case "complete":
4443
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_ink36.Text, { bold: true, color: "greenBright", children: "Smoke test passed." });
4480
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_ink36.Text, { bold: true, color: "greenBright", children: "Smoke test passed." });
4444
4481
  case "error":
4445
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4482
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4446
4483
  ErrorDisplay_default,
4447
4484
  {
4448
4485
  commandUsed,
@@ -4450,22 +4487,23 @@ function SmokeTestView({
4450
4487
  }
4451
4488
  );
4452
4489
  case "loading":
4453
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(LoadingText_default, { text: "Preparing smoke test" });
4490
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(LoadingText_default, { text: "Preparing smoke test" });
4454
4491
  case "progress":
4455
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TestProgress, { progress: state.progress });
4492
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TestProgress, { progress: state.progress });
4456
4493
  case "progress-error":
4457
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
4458
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(TestProgress, { progress: state.progress }),
4459
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4494
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
4495
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TestProgress, { progress: state.progress }),
4496
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4460
4497
  BuildError,
4461
4498
  {
4462
4499
  build: state.build,
4500
+ description: "Can't finish smoke test",
4463
4501
  message: (_d = (_c = state.progress) == null ? void 0 : _c.total) == null ? void 0 : _d.error
4464
4502
  }
4465
4503
  )
4466
4504
  ] });
4467
4505
  default:
4468
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4506
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4469
4507
  ErrorDisplay_default,
4470
4508
  {
4471
4509
  commandUsed,
@@ -4475,111 +4513,6 @@ function SmokeTestView({
4475
4513
  }
4476
4514
  }
4477
4515
 
4478
- // src/commands/smoke-test/utilities/build.ts
4479
- var import_semver = __toESM(require("semver"));
4480
-
4481
- // src/commands/smoke-test/utilities/SmokeError.ts
4482
- var SmokeError = class extends Error {
4483
- constructor(message2, { cause, type = "error" } = {}) {
4484
- super(message2, { cause });
4485
- this.type = type;
4486
- }
4487
- };
4488
-
4489
- // src/commands/smoke-test/utilities/build.ts
4490
- var MIN_RUNTIME_VERSION = "1.2.1-1";
4491
- function isBuildTestable(build) {
4492
- try {
4493
- validateBuild(build);
4494
- return true;
4495
- } catch (e) {
4496
- return false;
4497
- }
4498
- }
4499
- function isTestRunning(build) {
4500
- const { isFinished } = makeProgress(build);
4501
- return !isFinished;
4502
- }
4503
- function makeProgress(build) {
4504
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
4505
- const def = {
4506
- progress: 0,
4507
- state: "progress",
4508
- shouldSkip: false
4509
- };
4510
- const linux = {
4511
- ...((_a = build.smokeTest) == null ? void 0 : _a.linux) || def,
4512
- shouldSkip: ((_b = build.linux) == null ? void 0 : _b.shouldSkip) || false,
4513
- message: ((_d = (_c = build.smokeTest) == null ? void 0 : _c.linux) == null ? void 0 : _d.message) || "Starting"
4514
- };
4515
- const mac = {
4516
- ...((_e = build.smokeTest) == null ? void 0 : _e.mac) || def,
4517
- shouldSkip: ((_f = build.mac) == null ? void 0 : _f.shouldSkip) || false,
4518
- message: ((_h = (_g = build.smokeTest) == null ? void 0 : _g.mac) == null ? void 0 : _h.message) || "Starting"
4519
- };
4520
- const windows = {
4521
- ...((_i = build.smokeTest) == null ? void 0 : _i.windows) || def,
4522
- shouldSkip: ((_j = build.windows) == null ? void 0 : _j.shouldSkip) || false,
4523
- message: ((_l = (_k = build.smokeTest) == null ? void 0 : _k.windows) == null ? void 0 : _l.message) || "Starting"
4524
- };
4525
- const platforms = [linux, mac, windows].filter(
4526
- (p) => !p.shouldSkip && p.state !== "skipped"
4527
- );
4528
- const platformArr = ["mac", "windows", "linux"];
4529
- const isRunning = platformArr.some(
4530
- (platform) => {
4531
- var _a2;
4532
- return Boolean(
4533
- build.smokeTest && ((_a2 = build.smokeTest[platform]) == null ? void 0 : _a2.state) === "progress" && !build.smokeTest.isCanceled
4534
- );
4535
- }
4536
- );
4537
- const isFinished = !isRunning;
4538
- let totalState = "progress";
4539
- if ((_m = build.smokeTest) == null ? void 0 : _m.isCanceled) {
4540
- totalState = "canceled";
4541
- } else if (platforms.every((p) => p.state === "done")) {
4542
- totalState = "done";
4543
- } else if (isFinished && platforms.some((p) => p.state === "error")) {
4544
- totalState = "error";
4545
- }
4546
- return {
4547
- isFinished,
4548
- linux,
4549
- mac,
4550
- windows,
4551
- total: {
4552
- error: platforms.filter((p) => p.state === "error").map((p) => p.message).join("\n\n"),
4553
- state: totalState
4554
- }
4555
- };
4556
- }
4557
- function validateBuild(build) {
4558
- if (build.status !== "succeeded") {
4559
- throw new SmokeError(
4560
- `The build must be completed successfully. Actual build status: ${build.status}`
4561
- );
4562
- }
4563
- if (!build.todesktopRuntimeVersionSpecified) {
4564
- throw new SmokeError(
4565
- "The build has no todesktopRuntimeVersionSpecified set. Please make sure @todesktop/runtime is installed as a dependency and make a new build"
4566
- );
4567
- }
4568
- if (!isRuntimeVerRangeAllowed(build.todesktopRuntimeVersionSpecified)) {
4569
- throw new SmokeError(
4570
- `The build should have @todesktop/shared@${MIN_RUNTIME_VERSION} installed at least`
4571
- );
4572
- }
4573
- }
4574
- function isRuntimeVerRangeAllowed(runtimeVerRange) {
4575
- const minRuntimeVersionForApp = import_semver.default.minVersion(runtimeVerRange, {
4576
- loose: true
4577
- });
4578
- return import_semver.default.gte(minRuntimeVersionForApp, MIN_RUNTIME_VERSION, {
4579
- loose: true
4580
- });
4581
- }
4582
-
4583
4516
  // src/commands/smoke-test/utilities/cancelSmokeTest.ts
4584
4517
  async function cancelSmokeTest({
4585
4518
  appId,
@@ -4593,29 +4526,6 @@ async function cancelSmokeTest({
4593
4526
  });
4594
4527
  }
4595
4528
 
4596
- // src/commands/smoke-test/utilities/fetchBuild.ts
4597
- async function fetchBuild({
4598
- appId,
4599
- buildId,
4600
- userId
4601
- }) {
4602
- const build = await getBuildById({ appId, buildId, userId });
4603
- if (!build) {
4604
- throw new SmokeError(`No such build ${buildId} for application ${appId}`);
4605
- }
4606
- return build;
4607
- }
4608
-
4609
- // src/commands/smoke-test/utilities/fetchUserIdByAppId.ts
4610
- async function fetchUserIdByAppId(appId) {
4611
- try {
4612
- const { id: userId } = await findAppUserId_default(appId);
4613
- return userId;
4614
- } catch (e) {
4615
- throw new Error(`Can't fetch user for app ${appId}, ${e.message}`);
4616
- }
4617
- }
4618
-
4619
4529
  // src/commands/smoke-test/utilities/queueSmokeTest.ts
4620
4530
  async function queueSmokeTest({
4621
4531
  appId,
@@ -4667,7 +4577,7 @@ async function waitUntilFinished({
4667
4577
  }
4668
4578
 
4669
4579
  // src/commands/smoke-test/SmokeTestCommand.tsx
4670
- var import_jsx_runtime42 = require("react/jsx-runtime");
4580
+ var import_jsx_runtime43 = require("react/jsx-runtime");
4671
4581
  function SmokeTestCommand({
4672
4582
  buildId,
4673
4583
  configPath
@@ -4675,14 +4585,14 @@ function SmokeTestCommand({
4675
4585
  checkIfReactIsUsable_default();
4676
4586
  useAnalyticsCommand("smoke-test", { buildId, configPath });
4677
4587
  const command = `todesktop release ${buildId === "latest" ? "--latest" : "<id>"}`;
4678
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(LoginHOC_default, { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4588
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(LoginHOC_default, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4679
4589
  BuildPicker,
4680
4590
  {
4681
4591
  buildFilter: isBuildTestable,
4682
4592
  buildId,
4683
4593
  commandUsed: command,
4684
4594
  configPath,
4685
- children: (id) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4595
+ children: (id) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4686
4596
  SmokeTestContainer,
4687
4597
  {
4688
4598
  commandUsed: command,
@@ -4720,13 +4630,13 @@ function SmokeTestContainer({
4720
4630
  await cancelSmokeTest(state);
4721
4631
  }
4722
4632
  }
4723
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4633
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4724
4634
  Cancellation,
4725
4635
  {
4726
4636
  disabled: !isCancelable(state),
4727
4637
  onCancel,
4728
4638
  subject: "smoke test",
4729
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SmokeTestView, { commandUsed, state })
4639
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SmokeTestView, { commandUsed, state })
4730
4640
  }
4731
4641
  );
4732
4642
  }
@@ -4737,9 +4647,10 @@ async function smokeTestWorkflow({
4737
4647
  updateState
4738
4648
  }) {
4739
4649
  try {
4740
- const { id: appId, nodeVersion } = getProjectConfig(configPath).config;
4741
- const userId = await fetchUserIdByAppId(appId);
4742
- const build = await fetchBuild({ appId, buildId, userId });
4650
+ const { appId, build, nodeVersion, userId } = await getBuildAttributes({
4651
+ buildId,
4652
+ configPath
4653
+ });
4743
4654
  updateState({ appId, build, userId });
4744
4655
  validateBuild(build);
4745
4656
  if (!abortSignal.aborted && !isTestRunning(build)) {
@@ -4778,7 +4689,7 @@ function isCancelable(state) {
4778
4689
  // src/commands/WhoamiCommand.tsx
4779
4690
  var import_react23 = require("react");
4780
4691
  var import_ink37 = require("ink");
4781
- var import_jsx_runtime43 = require("react/jsx-runtime");
4692
+ var import_jsx_runtime44 = require("react/jsx-runtime");
4782
4693
  var WhoAmI = () => {
4783
4694
  const exit = useExit_default();
4784
4695
  checkIfReactIsUsable_default();
@@ -4790,11 +4701,11 @@ var WhoAmI = () => {
4790
4701
  }
4791
4702
  }, [exit, hasAttemptedTracking]);
4792
4703
  if (!auth || !auth.email) {
4793
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ink37.Text, { children: "You're not signed in" });
4704
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ink37.Text, { children: "You're not signed in" });
4794
4705
  }
4795
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_ink37.Text, { children: auth.email });
4706
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ink37.Text, { children: auth.email });
4796
4707
  };
4797
- var WhoAmIWrapper = () => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(LoginHOC_default, { isInteractive: false, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(WhoAmI, {}) }) });
4708
+ var WhoAmIWrapper = () => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(LoginHOC_default, { isInteractive: false, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(WhoAmI, {}) }) });
4798
4709
  var WhoamiCommand_default = WhoAmIWrapper;
4799
4710
 
4800
4711
  // src/utilities/exitIfCLIOutOfDate.ts
@@ -4835,7 +4746,7 @@ var package_default = {
4835
4746
  access: "public"
4836
4747
  },
4837
4748
  name: "@todesktop/cli",
4838
- version: "1.7.0-3",
4749
+ version: "1.7.0",
4839
4750
  license: "MIT",
4840
4751
  author: "Dave Jeffery <dave@todesktop.com> (http://www.todesktop.com/)",
4841
4752
  homepage: "https://todesktop.com/cli",
@@ -4852,10 +4763,10 @@ var package_default = {
4852
4763
  dev: "cp-cli dev.env .env && npm run build:dev && npm link",
4853
4764
  "dev:prod": "cp-cli prod.env .env && npm run build && npm link",
4854
4765
  build: "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli prod.env .env",
4855
- "build:dev": "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli prod.env .env",
4766
+ "build:dev": "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli dev.env .env",
4856
4767
  lint: "npm run lint:types && npm run lint:styles",
4857
- "lint:styles": "eslint src test .eslintrc.js",
4858
- "lint:types": "tsc",
4768
+ "lint:styles": "eslint src test .eslintrc.js && prettier --check .",
4769
+ "lint:types": "tsc && tsc-strict",
4859
4770
  "lint--fix": "eslint src test --fix",
4860
4771
  release: "npm run build && npx np --tag=latest",
4861
4772
  "release-beta": "npm run build && npx np --any-branch --no-tests --tag=beta",
@@ -4915,7 +4826,7 @@ var package_default = {
4915
4826
  "xdg-basedir": "^4.0.0"
4916
4827
  },
4917
4828
  devDependencies: {
4918
- "@todesktop/shared": "^7.179.0",
4829
+ "@todesktop/shared": "^7.180.0",
4919
4830
  "@types/bunyan": "^1.8.6",
4920
4831
  "@types/react": "^18.0.26",
4921
4832
  "@typescript-eslint/eslint-plugin": "^5.46.1",
@@ -4942,7 +4853,8 @@ var package_default = {
4942
4853
  prettier: "^2.8.1",
4943
4854
  proxyquire: "^2.1.3",
4944
4855
  sinon: "^9.0.3",
4945
- typescript: "^4.9.4"
4856
+ typescript: "^4.9.4",
4857
+ "typescript-strict-plugin": "^2.1.0"
4946
4858
  },
4947
4859
  ava: {
4948
4860
  extensions: [
@@ -5049,13 +4961,13 @@ var onCommand_default = ({ sentry = true, exitIfOutOfDate = true } = {}) => {
5049
4961
  };
5050
4962
 
5051
4963
  // src/index.ts
5052
- var parseCount = (value) => {
4964
+ function parseCount(value) {
5053
4965
  const parsedValue = Number.parseInt(value, 10);
5054
4966
  if (parsedValue > 0) {
5055
4967
  return parsedValue;
5056
4968
  }
5057
4969
  throw new import_commander.InvalidArgumentError("Should be a positive number");
5058
- };
4970
+ }
5059
4971
  var configOption = new import_commander.Option(
5060
4972
  "--config [string]",
5061
4973
  "Path to a different configuration file. If not specified, `todesktop.json` in the project root will be used"
@@ -5068,7 +4980,7 @@ import_commander.program.command("build").description(
5068
4980
  "Whether or not code-signing and notarization should be performed. Disable this for quicker builds"
5069
4981
  ).addOption(configOption).action(({ codeSign, config: config2 }) => {
5070
4982
  runCommand(BuildCommand_default, {
5071
- shouldCodeSign: codeSign,
4983
+ shouldCodeSign: codeSign !== "false",
5072
4984
  configPath: config2
5073
4985
  });
5074
4986
  });
@@ -5091,11 +5003,10 @@ import_commander.program.command("logout").description("Logs you out").action(()
5091
5003
  runCommand(LogoutCommand_default, null, { exitIfOutOfDate: false });
5092
5004
  });
5093
5005
  import_commander.program.command("release").description("Release a build").argument("[id]", "A specific build ID to release").option("--force", "Skips interactive confirmation step").option("--latest", "Release the latest build").addOption(configOption).action((id, { config: config2, force, latest }) => {
5094
- runCommand(ReleaseCommand_default, {
5006
+ runCommand(ReleaseCommand, {
5095
5007
  configPath: config2,
5096
- force,
5097
- id,
5098
- shouldReleaseLatest: latest
5008
+ shouldConfirm: !force,
5009
+ buildId: latest ? "latest" : id
5099
5010
  });
5100
5011
  });
5101
5012
  import_commander.program.command("smoke-test").description("Check whether the build works and can be successfully updated").argument("[id]", "A specific build ID to test").option("--latest", "Release the latest build").addOption(configOption).action((id, { config: config2, latest }) => {