eas-cli 2.5.1 → 2.7.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 (150) hide show
  1. package/README.md +8 -1095
  2. package/build/branch/queries.d.ts +8 -1
  3. package/build/branch/queries.js +53 -23
  4. package/build/build/android/build.js +1 -0
  5. package/build/build/ios/build.js +1 -0
  6. package/build/build/local.js +1 -1
  7. package/build/build/queries.d.ts +11 -1
  8. package/build/build/queries.js +39 -1
  9. package/build/build/validate.d.ts +1 -0
  10. package/build/build/validate.js +121 -1
  11. package/build/channel/queries.d.ts +11 -0
  12. package/build/channel/queries.js +51 -9
  13. package/build/channel/utils.js +22 -22
  14. package/build/commandUtils/context/LoggedInContextField.d.ts +3 -0
  15. package/build/commandUtils/context/LoggedInContextField.js +9 -1
  16. package/build/commandUtils/context/MaybeLoggedInContextField.d.ts +3 -0
  17. package/build/commandUtils/context/MaybeLoggedInContextField.js +9 -1
  18. package/build/commandUtils/context/contextUtils/createGraphqlClient.d.ts +2 -2
  19. package/build/commandUtils/context/contextUtils/getProjectIdAsync.js +1 -1
  20. package/build/commandUtils/gating/FeatureGateEnvOverrides.d.ts +7 -0
  21. package/build/commandUtils/gating/FeatureGateEnvOverrides.js +35 -0
  22. package/build/commandUtils/gating/FeatureGateKey.d.ts +4 -0
  23. package/build/commandUtils/gating/FeatureGateKey.js +11 -0
  24. package/build/commandUtils/gating/FeatureGateTestOverrides.d.ts +5 -0
  25. package/build/commandUtils/gating/FeatureGateTestOverrides.js +17 -0
  26. package/build/commandUtils/gating/FeatureGating.d.ts +16 -0
  27. package/build/commandUtils/gating/FeatureGating.js +55 -0
  28. package/build/commandUtils/pagination.d.ts +4 -3
  29. package/build/commands/branch/create.d.ts +0 -3
  30. package/build/commands/branch/create.js +2 -27
  31. package/build/commands/branch/list.d.ts +1 -1
  32. package/build/commands/branch/view.d.ts +1 -1
  33. package/build/commands/build/configure.d.ts +1 -1
  34. package/build/commands/build/index.d.ts +2 -2
  35. package/build/commands/build/list.d.ts +4 -4
  36. package/build/commands/build/list.js +2 -15
  37. package/build/commands/build/run.d.ts +21 -0
  38. package/build/commands/build/run.js +149 -0
  39. package/build/commands/build/version/set.d.ts +1 -1
  40. package/build/commands/build/version/sync.d.ts +1 -1
  41. package/build/commands/channel/create.d.ts +0 -7
  42. package/build/commands/channel/create.js +4 -31
  43. package/build/commands/channel/list.d.ts +1 -1
  44. package/build/commands/channel/view.d.ts +1 -1
  45. package/build/commands/config.d.ts +1 -1
  46. package/build/commands/credentials.d.ts +1 -1
  47. package/build/commands/device/list.d.ts +1 -1
  48. package/build/commands/metadata/lint.d.ts +12 -0
  49. package/build/commands/metadata/lint.js +72 -0
  50. package/build/commands/metadata/pull.js +20 -9
  51. package/build/commands/metadata/push.js +20 -9
  52. package/build/commands/secret/create.d.ts +1 -1
  53. package/build/commands/secret/list.js +12 -17
  54. package/build/commands/submit.d.ts +1 -1
  55. package/build/commands/update/configure.d.ts +1 -0
  56. package/build/commands/update/configure.js +10 -216
  57. package/build/commands/update/index.d.ts +3 -9
  58. package/build/commands/update/index.js +136 -143
  59. package/build/commands/update/list.d.ts +1 -1
  60. package/build/commands/webhook/create.d.ts +1 -1
  61. package/build/commands/webhook/list.d.ts +1 -1
  62. package/build/commands/webhook/update.d.ts +1 -1
  63. package/build/devices/actions/create/inputMethod.js +2 -15
  64. package/build/devices/utils/formatDevice.d.ts +2 -0
  65. package/build/devices/utils/formatDevice.js +32 -7
  66. package/build/env.d.ts +8 -0
  67. package/build/env.js +8 -0
  68. package/build/graphql/generated.d.ts +100 -23
  69. package/build/graphql/generated.js +10 -2
  70. package/build/graphql/mutations/KeystoreGenerationUrlMutation.js +1 -1
  71. package/build/graphql/queries/UserQuery.js +2 -2
  72. package/build/graphql/types/Build.js +2 -0
  73. package/build/log.d.ts +1 -0
  74. package/build/log.js +3 -0
  75. package/build/metadata/apple/rules/index.d.ts +1 -0
  76. package/build/metadata/apple/rules/index.js +6 -0
  77. package/build/metadata/apple/rules/infoKeywordLength.d.ts +6 -0
  78. package/build/metadata/apple/rules/infoKeywordLength.js +35 -0
  79. package/build/metadata/apple/rules/infoRestrictedWords.d.ts +6 -0
  80. package/build/metadata/apple/rules/infoRestrictedWords.js +57 -0
  81. package/build/metadata/apple/tasks/index.d.ts +1 -2
  82. package/build/metadata/apple/tasks/index.js +1 -1
  83. package/build/metadata/auth.d.ts +21 -0
  84. package/build/metadata/auth.js +33 -0
  85. package/build/metadata/config/issue.d.ts +21 -0
  86. package/build/metadata/config/issue.js +9 -0
  87. package/build/metadata/config/resolve.d.ts +27 -0
  88. package/build/metadata/{config.js → config/resolve.js} +24 -25
  89. package/build/metadata/config/schema.d.ts +7 -0
  90. package/build/metadata/config/schema.js +2 -0
  91. package/build/metadata/config/validate.d.ts +3 -0
  92. package/build/metadata/config/validate.js +47 -0
  93. package/build/metadata/download.d.ts +11 -2
  94. package/build/metadata/download.js +14 -9
  95. package/build/metadata/errors.d.ts +3 -3
  96. package/build/metadata/errors.js +3 -1
  97. package/build/metadata/upload.d.ts +11 -2
  98. package/build/metadata/upload.js +16 -11
  99. package/build/metadata/utils/ajv.d.ts +10 -0
  100. package/build/metadata/utils/ajv.js +30 -0
  101. package/build/metadata/utils/telemetry.js +6 -6
  102. package/build/project/projectUtils.d.ts +3 -1
  103. package/build/project/projectUtils.js +10 -3
  104. package/build/project/publish.d.ts +13 -10
  105. package/build/project/publish.js +68 -38
  106. package/build/project/workflow.d.ts +1 -0
  107. package/build/project/workflow.js +9 -1
  108. package/build/run/android/run.d.ts +1 -0
  109. package/build/run/android/run.js +9 -0
  110. package/build/run/ios/run.d.ts +1 -0
  111. package/build/run/ios/run.js +31 -0
  112. package/build/run/ios/simctl.d.ts +2 -0
  113. package/build/run/ios/simctl.js +8 -0
  114. package/build/run/ios/simulator.d.ts +21 -0
  115. package/build/run/ios/simulator.js +161 -0
  116. package/build/run/ios/systemRequirements.d.ts +1 -0
  117. package/build/run/ios/systemRequirements.js +82 -0
  118. package/build/run/ios/xcode.d.ts +4 -0
  119. package/build/run/ios/xcode.js +41 -0
  120. package/build/run/ios/xcrun.d.ts +4 -0
  121. package/build/run/ios/xcrun.js +68 -0
  122. package/build/run/run.d.ts +8 -0
  123. package/build/run/run.js +15 -0
  124. package/build/submit/ArchiveSource.js +12 -16
  125. package/build/submit/utils/summary.d.ts +1 -1
  126. package/build/update/configure.d.ts +22 -0
  127. package/build/update/configure.js +200 -0
  128. package/build/update/queries.js +30 -39
  129. package/build/update/utils.d.ts +8 -1
  130. package/build/update/utils.js +35 -1
  131. package/build/utils/buildDistribution.d.ts +3 -0
  132. package/build/utils/buildDistribution.js +20 -0
  133. package/build/utils/download.d.ts +2 -0
  134. package/build/utils/download.js +114 -0
  135. package/build/utils/expoCli.d.ts +6 -0
  136. package/build/utils/expoCli.js +46 -1
  137. package/build/utils/expodash/filter.d.ts +2 -0
  138. package/build/utils/expodash/filter.js +8 -0
  139. package/build/utils/expodash/memoize.d.ts +2 -0
  140. package/build/utils/expodash/memoize.js +17 -0
  141. package/build/utils/formatFields.d.ts +3 -2
  142. package/build/utils/image.d.ts +6 -0
  143. package/build/utils/image.js +107 -0
  144. package/build/utils/statuspageService.js +1 -0
  145. package/oclif.manifest.json +1 -1
  146. package/package.json +36 -30
  147. package/schema/metadata-0.json +1 -1
  148. package/build/metadata/config.d.ts +0 -41
  149. package/build/metadata/context.d.ts +0 -50
  150. package/build/metadata/context.js +0 -47
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAsync = void 0;
4
+ const generated_1 = require("../graphql/generated");
5
+ const run_1 = require("./android/run");
6
+ const run_2 = require("./ios/run");
7
+ async function runAsync(simulatorBuildPath, selectedPlatform) {
8
+ if (selectedPlatform === generated_1.AppPlatform.Ios) {
9
+ await (0, run_2.runAppOnIosSimulatorAsync)(simulatorBuildPath);
10
+ }
11
+ else {
12
+ await (0, run_1.runAppOnAndroidEmulatorAsync)(simulatorBuildPath);
13
+ }
14
+ }
15
+ exports.runAsync = runAsync;
@@ -6,12 +6,12 @@ const eas_build_job_1 = require("@expo/eas-build-job");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
7
  const url_1 = require("url");
8
8
  const uuid = tslib_1.__importStar(require("uuid"));
9
- const generated_1 = require("../graphql/generated");
10
9
  const BuildQuery_1 = require("../graphql/queries/BuildQuery");
11
10
  const AppPlatform_1 = require("../graphql/types/AppPlatform");
12
11
  const log_1 = tslib_1.__importStar(require("../log"));
13
12
  const platform_1 = require("../platform");
14
13
  const prompts_1 = require("../prompts");
14
+ const date_1 = require("../utils/date");
15
15
  const builds_1 = require("./utils/builds");
16
16
  const files_1 = require("./utils/files");
17
17
  exports.BUILD_LIST_ITEM_COUNT = 4;
@@ -187,26 +187,22 @@ async function handleBuildListSourceAsync(graphqlClient, source) {
187
187
  }
188
188
  }
189
189
  function formatBuildChoice(build, expiryDate) {
190
- const { id, platform, updatedAt, appVersion, sdkVersion, runtimeVersion, buildProfile, appBuildVersion, releaseChannel, initiatingActor, } = build;
190
+ const { id, updatedAt, runtimeVersion, buildProfile, gitCommitHash, gitCommitMessage, channel } = build;
191
191
  const formatValue = (field) => field ? chalk_1.default.bold(field) : chalk_1.default.dim('Unknown');
192
192
  const buildDate = new Date(updatedAt);
193
- const maybeRuntimeVersion = runtimeVersion ? `Runtime: ${formatValue(runtimeVersion)}` : null;
194
- const maybeSdkVersion = sdkVersion ? `SDK: ${formatValue(sdkVersion)}` : null;
195
- const appBuildVersionString = `${platform === generated_1.AppPlatform.Android ? 'Version code' : 'Build number'}: ${formatValue(appBuildVersion)}`;
196
- const title = [
197
- `ID: ${chalk_1.default.dim(id)}, Finished at: ${chalk_1.default.bold(buildDate.toLocaleString())}`,
198
- [
199
- `\tApp version: ${formatValue(appVersion)}, ${appBuildVersionString}`,
200
- maybeRuntimeVersion,
201
- maybeSdkVersion,
202
- ]
203
- .filter(it => it != null)
204
- .join(', '),
205
- `\tProfile: ${formatValue(buildProfile)}, Release channel: ${formatValue(releaseChannel)}`,
206
- `\tAuthored by: ${formatValue(initiatingActor === null || initiatingActor === void 0 ? void 0 : initiatingActor.displayName)}`,
193
+ const formattedCommitData = gitCommitHash && gitCommitMessage
194
+ ? `${chalk_1.default.dim(gitCommitHash.slice(0, 7))} "${chalk_1.default.bold(gitCommitMessage)}"`
195
+ : 'Unknown';
196
+ const title = `ID: ${chalk_1.default.dim(id)} (${chalk_1.default.dim(`${(0, date_1.fromNow)(buildDate)} ago`)})`;
197
+ const description = [
198
+ `\tProfile: ${formatValue(buildProfile)}`,
199
+ `\tChannel: ${formatValue(channel)}`,
200
+ `\tRuntime version: ${formatValue(runtimeVersion)}`,
201
+ `\tCommit: ${formattedCommitData}`,
207
202
  ].join('\n');
208
203
  return {
209
204
  title,
205
+ description,
210
206
  value: build,
211
207
  disabled: buildDate < expiryDate,
212
208
  };
@@ -5,4 +5,4 @@ export interface ArchiveSourceSummaryFields {
5
5
  formattedBuild?: string;
6
6
  }
7
7
  export declare function formatArchiveSourceSummary({ source, build }: Archive): ArchiveSourceSummaryFields;
8
- export declare function printSummary<T>(summary: T, keyMap: Record<keyof T, string>): void;
8
+ export declare function printSummary<T extends object>(summary: T, keyMap: Record<keyof T, string>): void;
@@ -0,0 +1,22 @@
1
+ import { ExpoConfig } from '@expo/config-types';
2
+ import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
3
+ import { RequestedPlatform } from '../platform';
4
+ export declare const DEFAULT_MANAGED_RUNTIME_VERSION: {
5
+ readonly policy: "sdkVersion";
6
+ };
7
+ export declare const DEFAULT_BARE_RUNTIME_VERSION: "1.0.0";
8
+ /**
9
+ * Make sure EAS Update is fully configured in the current project.
10
+ * This goes over a checklist and performs the following checks or changes:
11
+ * - Enure the `expo-updates` package is currently installed.
12
+ * - Ensure `app.json` is configured for EAS Updates
13
+ * - Sets `runtimeVersion` if not set
14
+ * - Sets `updates.url` if not set
15
+ * - Ensure latest changes are reflected in the native config, if any
16
+ */
17
+ export declare function ensureEASUpdatesIsConfiguredAsync(graphqlClient: ExpoGraphqlClient, { exp: expWithoutUpdates, projectId, projectDir, platform, }: {
18
+ exp: ExpoConfig;
19
+ projectId: string;
20
+ projectDir: string;
21
+ platform: RequestedPlatform | null;
22
+ }): Promise<void>;
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureEASUpdatesIsConfiguredAsync = exports.DEFAULT_BARE_RUNTIME_VERSION = exports.DEFAULT_MANAGED_RUNTIME_VERSION = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const config_1 = require("@expo/config");
6
+ const eas_build_job_1 = require("@expo/eas-build-job");
7
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
+ const api_1 = require("../api");
9
+ const generated_1 = require("../graphql/generated");
10
+ const log_1 = tslib_1.__importStar(require("../log"));
11
+ const platform_1 = require("../platform");
12
+ const projectUtils_1 = require("../project/projectUtils");
13
+ const workflow_1 = require("../project/workflow");
14
+ const UpdatesModule_1 = require("./android/UpdatesModule");
15
+ const UpdatesModule_2 = require("./ios/UpdatesModule");
16
+ exports.DEFAULT_MANAGED_RUNTIME_VERSION = { policy: 'sdkVersion' };
17
+ exports.DEFAULT_BARE_RUNTIME_VERSION = '1.0.0';
18
+ function getDefaultRuntimeVersion(workflow) {
19
+ return workflow === eas_build_job_1.Workflow.GENERIC
20
+ ? exports.DEFAULT_BARE_RUNTIME_VERSION
21
+ : exports.DEFAULT_MANAGED_RUNTIME_VERSION;
22
+ }
23
+ function isRuntimeEqual(runtimeVersionA, runtimeVersionB) {
24
+ if (typeof runtimeVersionA === 'string' && typeof runtimeVersionB === 'string') {
25
+ return runtimeVersionA === runtimeVersionB;
26
+ }
27
+ else if (typeof runtimeVersionA === 'object' && typeof runtimeVersionB === 'object') {
28
+ return runtimeVersionA.policy === runtimeVersionB.policy;
29
+ }
30
+ else {
31
+ return false;
32
+ }
33
+ }
34
+ function replaceUndefinedObjectValues(value, replacement) {
35
+ for (const key in value) {
36
+ if (value[key] === undefined) {
37
+ value[key] = replacement;
38
+ }
39
+ else if (typeof value[key] === 'object') {
40
+ value[key] = replaceUndefinedObjectValues(value[key], replacement);
41
+ }
42
+ }
43
+ return value;
44
+ }
45
+ /**
46
+ * Partially merge the EAS Update config with the existing Expo config.
47
+ * This preserves and merges the nested update-related properties.
48
+ */
49
+ function mergeExpoConfig(exp, modifyExp) {
50
+ var _a;
51
+ return {
52
+ runtimeVersion: (_a = modifyExp.runtimeVersion) !== null && _a !== void 0 ? _a : exp.runtimeVersion,
53
+ updates: { ...exp.updates, ...modifyExp.updates },
54
+ android: {
55
+ ...exp.android,
56
+ ...modifyExp.android,
57
+ },
58
+ ios: {
59
+ ...exp.ios,
60
+ ...modifyExp.ios,
61
+ },
62
+ };
63
+ }
64
+ /**
65
+ * Make sure the `app.json` is configured to use EAS Updates.
66
+ * This does a couple of things:
67
+ * - Ensure update URL is set to the project EAS endpoint
68
+ * - Ensure runtimeVersion is defined for both or individual platforms
69
+ * - Output the changes made, or the changes required to make manually
70
+ */
71
+ async function ensureEASUpdatesIsConfiguredInExpoConfigAsync({ exp, projectId, projectDir, platform, workflows, }) {
72
+ var _a, _b, _c, _d, _e, _f;
73
+ const modifyConfig = {};
74
+ if (((_a = exp.updates) === null || _a === void 0 ? void 0 : _a.url) !== (0, api_1.getEASUpdateURL)(projectId)) {
75
+ modifyConfig.updates = { url: (0, api_1.getEASUpdateURL)(projectId) };
76
+ }
77
+ let androidRuntimeVersion = (_c = (_b = exp.android) === null || _b === void 0 ? void 0 : _b.runtimeVersion) !== null && _c !== void 0 ? _c : exp.runtimeVersion;
78
+ let iosRuntimeVersion = (_e = (_d = exp.ios) === null || _d === void 0 ? void 0 : _d.runtimeVersion) !== null && _e !== void 0 ? _e : exp.runtimeVersion;
79
+ if ((['all', 'android'].includes(platform) && !androidRuntimeVersion) ||
80
+ (['all', 'ios'].includes(platform) && !iosRuntimeVersion)) {
81
+ androidRuntimeVersion = androidRuntimeVersion !== null && androidRuntimeVersion !== void 0 ? androidRuntimeVersion : getDefaultRuntimeVersion(workflows.android);
82
+ iosRuntimeVersion = iosRuntimeVersion !== null && iosRuntimeVersion !== void 0 ? iosRuntimeVersion : getDefaultRuntimeVersion(workflows.ios);
83
+ if (platform === 'all' && isRuntimeEqual(androidRuntimeVersion, iosRuntimeVersion)) {
84
+ modifyConfig.runtimeVersion = androidRuntimeVersion;
85
+ }
86
+ else {
87
+ if (['all', 'android'].includes(platform)) {
88
+ modifyConfig.runtimeVersion = undefined;
89
+ modifyConfig.android = { runtimeVersion: androidRuntimeVersion };
90
+ }
91
+ if (['all', 'ios'].includes(platform)) {
92
+ modifyConfig.runtimeVersion = undefined;
93
+ modifyConfig.ios = { runtimeVersion: iosRuntimeVersion };
94
+ }
95
+ }
96
+ }
97
+ if (Object.keys(modifyConfig).length === 0) {
98
+ return { exp, projectChanged: false };
99
+ }
100
+ const mergedExp = mergeExpoConfig(exp, modifyConfig);
101
+ const result = await (0, config_1.modifyConfigAsync)(projectDir, mergedExp);
102
+ switch (result.type) {
103
+ case 'success':
104
+ logEasUpdatesAutoConfig({ exp, modifyConfig });
105
+ return {
106
+ projectChanged: true,
107
+ // TODO(cedric): fix return type of `modifyConfigAsync` to avoid `null` for type === success repsonses
108
+ exp: (_f = result.config) === null || _f === void 0 ? void 0 : _f.expo,
109
+ };
110
+ case 'warn':
111
+ warnEASUpdatesManualConfig({ modifyConfig, workflows });
112
+ throw new Error(result.message);
113
+ case 'fail':
114
+ throw new Error(result.message);
115
+ default:
116
+ throw new Error(`Unexpected result type "${result.type}" received when modifying the project config.`);
117
+ }
118
+ }
119
+ function logEasUpdatesAutoConfig({ modifyConfig, exp, }) {
120
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
121
+ if ((_a = modifyConfig.updates) === null || _a === void 0 ? void 0 : _a.url) {
122
+ log_1.default.withTick(((_b = exp.updates) === null || _b === void 0 ? void 0 : _b.url)
123
+ ? `Overwrote updates.url "${exp.updates.url}" with "${modifyConfig.updates.url}"`
124
+ : `Configured updates.url to "${modifyConfig.updates.url}"`);
125
+ }
126
+ if ((_d = (_c = modifyConfig.android) === null || _c === void 0 ? void 0 : _c.runtimeVersion) !== null && _d !== void 0 ? _d : modifyConfig.runtimeVersion) {
127
+ log_1.default.withTick(`Configured runtimeVersion for ${platform_1.appPlatformDisplayNames[generated_1.AppPlatform.Android]} with "${JSON.stringify((_f = (_e = modifyConfig.android) === null || _e === void 0 ? void 0 : _e.runtimeVersion) !== null && _f !== void 0 ? _f : modifyConfig.runtimeVersion)}"`);
128
+ }
129
+ if ((_h = (_g = modifyConfig.ios) === null || _g === void 0 ? void 0 : _g.runtimeVersion) !== null && _h !== void 0 ? _h : modifyConfig.runtimeVersion) {
130
+ log_1.default.withTick(`Configured runtimeVersion for ${platform_1.appPlatformDisplayNames[generated_1.AppPlatform.Ios]} with "${JSON.stringify((_k = (_j = modifyConfig.ios) === null || _j === void 0 ? void 0 : _j.runtimeVersion) !== null && _k !== void 0 ? _k : modifyConfig.runtimeVersion)}"`);
131
+ }
132
+ }
133
+ function warnEASUpdatesManualConfig({ modifyConfig, workflows, }) {
134
+ log_1.default.addNewLineIfNone();
135
+ log_1.default.warn(`It looks like you are using a dynamic configuration! ${(0, log_1.learnMore)('https://docs.expo.dev/workflow/configuration/#dynamic-configuration-with-appconfigjs)')}`);
136
+ log_1.default.warn(`Finish configuring EAS Update by adding the following to the project app.config.js:\n${(0, log_1.learnMore)('https://expo.fyi/eas-update-config')}\n`);
137
+ log_1.default.log(chalk_1.default.bold(JSON.stringify(replaceUndefinedObjectValues(modifyConfig, '<remove this key>'), null, 2)));
138
+ log_1.default.addNewLineIfNone();
139
+ if (workflows.android === eas_build_job_1.Workflow.GENERIC || workflows.ios === eas_build_job_1.Workflow.GENERIC) {
140
+ log_1.default.warn((0, chalk_1.default) `The native config files {bold Expo.plist & AndroidManifest.xml} must be updated to support EAS Update. ${(0, log_1.learnMore)('https://expo.fyi/eas-update-config.md#native-configuration')}`);
141
+ }
142
+ log_1.default.addNewLineIfNone();
143
+ }
144
+ /**
145
+ * Make sure that the current `app.json` configuration for EAS Updates is set natively.
146
+ */
147
+ async function ensureEASUpdatesIsConfiguredNativelyAsync(graphqlClient, { exp, projectId, projectDir, platform, workflows, }) {
148
+ if (['all', 'android'].includes(platform) && workflows.android === eas_build_job_1.Workflow.GENERIC) {
149
+ await (0, UpdatesModule_1.syncUpdatesConfigurationAsync)(graphqlClient, projectDir, exp, projectId);
150
+ log_1.default.withTick(`Configured ${chalk_1.default.bold('AndroidManifest.xml')} for EAS Update`);
151
+ }
152
+ if (['all', 'ios'].includes(platform) && workflows.ios === eas_build_job_1.Workflow.GENERIC) {
153
+ await (0, UpdatesModule_2.syncUpdatesConfigurationAsync)(graphqlClient, projectDir, exp, projectId);
154
+ log_1.default.withTick(`Configured ${chalk_1.default.bold('Expo.plist')} for EAS Update`);
155
+ }
156
+ }
157
+ /**
158
+ * Make sure EAS Update is fully configured in the current project.
159
+ * This goes over a checklist and performs the following checks or changes:
160
+ * - Enure the `expo-updates` package is currently installed.
161
+ * - Ensure `app.json` is configured for EAS Updates
162
+ * - Sets `runtimeVersion` if not set
163
+ * - Sets `updates.url` if not set
164
+ * - Ensure latest changes are reflected in the native config, if any
165
+ */
166
+ async function ensureEASUpdatesIsConfiguredAsync(graphqlClient, { exp: expWithoutUpdates, projectId, projectDir, platform, }) {
167
+ const hasExpoUpdates = (0, projectUtils_1.isExpoUpdatesInstalledOrAvailable)(projectDir, expWithoutUpdates.sdkVersion);
168
+ if (!hasExpoUpdates) {
169
+ await (0, projectUtils_1.installExpoUpdatesAsync)(projectDir, { silent: !log_1.default.isDebug });
170
+ log_1.default.withTick('Installed expo updates');
171
+ }
172
+ // Bail out if using a platform that doesn't require runtime versions
173
+ // or native setup, i.e. web.
174
+ if (!platform) {
175
+ return;
176
+ }
177
+ const workflows = await (0, workflow_1.resolveWorkflowPerPlatformAsync)(projectDir);
178
+ const { projectChanged, exp: expWithUpdates } = await ensureEASUpdatesIsConfiguredInExpoConfigAsync({
179
+ exp: expWithoutUpdates,
180
+ projectDir,
181
+ projectId,
182
+ platform,
183
+ workflows,
184
+ });
185
+ if (projectChanged || !hasExpoUpdates) {
186
+ await ensureEASUpdatesIsConfiguredNativelyAsync(graphqlClient, {
187
+ exp: expWithUpdates,
188
+ projectDir,
189
+ projectId,
190
+ platform,
191
+ workflows,
192
+ });
193
+ }
194
+ if (projectChanged) {
195
+ log_1.default.addNewLineIfNone();
196
+ log_1.default.warn(`All builds of your app going forward will be eligible to receive updates published with EAS Update.`);
197
+ log_1.default.newLine();
198
+ }
199
+ }
200
+ exports.ensureEASUpdatesIsConfiguredAsync = ensureEASUpdatesIsConfiguredAsync;
@@ -4,7 +4,6 @@ exports.selectUpdateGroupOnBranchAsync = exports.listAndRenderUpdateGroupsOnBran
4
4
  const tslib_1 = require("tslib");
5
5
  const assert_1 = tslib_1.__importDefault(require("assert"));
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
- const cli_table3_1 = tslib_1.__importDefault(require("cli-table3"));
8
7
  const UpdateQuery_1 = require("../graphql/queries/UpdateQuery");
9
8
  const log_1 = tslib_1.__importDefault(require("../log"));
10
9
  const formatFields_1 = tslib_1.__importDefault(require("../utils/formatFields"));
@@ -21,7 +20,7 @@ async function listAndRenderUpdateGroupsOnAppAsync(graphqlClient, { projectId, p
21
20
  offset: paginatedQueryOptions.offset,
22
21
  appId: projectId,
23
22
  });
24
- renderUpdateGroupsOnAppAsTable(updateGroups, paginatedQueryOptions);
23
+ renderUpdateGroupsOnApp({ updateGroups, paginatedQueryOptions });
25
24
  }
26
25
  else {
27
26
  await (0, queries_1.paginatedQueryWithConfirmPromptAsync)({
@@ -30,7 +29,7 @@ async function listAndRenderUpdateGroupsOnAppAsync(graphqlClient, { projectId, p
30
29
  queryToPerform: (limit, offset) => queryUpdateGroupsOnAppAsync(graphqlClient, { limit, offset, appId: projectId }),
31
30
  promptOptions: {
32
31
  title: 'Load more update groups?',
33
- renderListItems: updateGroups => renderUpdateGroupsOnAppAsTable(updateGroups, paginatedQueryOptions),
32
+ renderListItems: updateGroups => renderUpdateGroupsOnApp({ updateGroups, paginatedQueryOptions }),
34
33
  },
35
34
  });
36
35
  }
@@ -45,7 +44,7 @@ async function listAndRenderUpdateGroupsOnBranchAsync(graphqlClient, { projectId
45
44
  appId: projectId,
46
45
  branchName,
47
46
  });
48
- renderUpdateGroupsOnBranchAsTable({ updateGroups, branchName, paginatedQueryOptions });
47
+ renderUpdateGroupsOnBranch({ updateGroups, branchName, paginatedQueryOptions });
49
48
  }
50
49
  else {
51
50
  await (0, queries_1.paginatedQueryWithConfirmPromptAsync)({
@@ -59,7 +58,7 @@ async function listAndRenderUpdateGroupsOnBranchAsync(graphqlClient, { projectId
59
58
  }),
60
59
  promptOptions: {
61
60
  title: 'Load more update groups?',
62
- renderListItems: updateGroups => renderUpdateGroupsOnBranchAsTable({ updateGroups, branchName, paginatedQueryOptions }),
61
+ renderListItems: updateGroups => renderUpdateGroupsOnBranch({ updateGroups, branchName, paginatedQueryOptions }),
63
62
  },
64
63
  });
65
64
  }
@@ -97,52 +96,44 @@ async function queryUpdateGroupsOnBranchAsync(graphqlClient, args) {
97
96
  async function queryUpdateGroupsOnAppAsync(graphqlClient, args) {
98
97
  return await UpdateQuery_1.UpdateQuery.viewUpdateGroupsOnAppAsync(graphqlClient, args);
99
98
  }
100
- function renderUpdateGroupsOnBranchAsTable({ updateGroups, branchName, paginatedQueryOptions: { json }, }) {
99
+ function renderUpdateGroupsOnBranch({ branchName, updateGroups, paginatedQueryOptions: { json }, }) {
101
100
  var _a, _b;
101
+ // Ensure all updates are from the same branch
102
102
  const branchNames = updateGroups.flatMap(updateGroup => updateGroup.map(update => update.branch.name));
103
103
  (0, assert_1.default)(branchNames.every(name => name === branchName), 'Each update must belong to the same branch.');
104
+ const updateGroupDescriptions = (0, utils_1.getUpdateGroupDescriptionsWithBranch)(updateGroups);
104
105
  const branch = {
105
106
  name: branchName,
106
107
  id: (_b = (_a = updateGroups[0]) === null || _a === void 0 ? void 0 : _a[0].branch.id) !== null && _b !== void 0 ? _b : 'N/A',
107
108
  };
108
- const updateGroupDescriptions = (0, utils_1.getUpdateGroupDescriptions)(updateGroups);
109
109
  if (json) {
110
- (0, json_1.printJsonOnlyOutput)({ ...branch, currentPage: updateGroupDescriptions });
111
- }
112
- else {
113
- const updateGroupsTable = new cli_table3_1.default({
114
- head: utils_1.UPDATE_COLUMNS,
115
- wordWrap: true,
116
- });
117
- updateGroupDescriptions.forEach(({ message, runtimeVersion, group, platforms }) => {
118
- updateGroupsTable.push([message, runtimeVersion, group, platforms]);
119
- });
120
- log_1.default.addNewLineIfNone();
121
- log_1.default.log(chalk_1.default.bold('Branch:'));
122
- log_1.default.log((0, formatFields_1.default)([
123
- { label: 'Name', value: branch.name },
124
- { label: 'ID', value: branch.id },
125
- ]));
126
- log_1.default.addNewLineIfNone();
127
- log_1.default.log(updateGroupsTable.toString());
110
+ return (0, json_1.printJsonOnlyOutput)({ ...branch, currentPage: updateGroupDescriptions });
128
111
  }
112
+ log_1.default.addNewLineIfNone();
113
+ log_1.default.log(chalk_1.default.bold('Branch:'));
114
+ log_1.default.log((0, formatFields_1.default)([
115
+ { label: 'Name', value: branch.name },
116
+ { label: 'ID', value: branch.id },
117
+ ]));
118
+ log_1.default.newLine();
119
+ log_1.default.log(chalk_1.default.bold('Recent update groups:'));
120
+ log_1.default.newLine();
121
+ log_1.default.log(updateGroupDescriptions
122
+ .map(description => (0, utils_1.formatUpdateGroup)(description))
123
+ .join(`\n\n${chalk_1.default.dim('———')}\n\n`));
129
124
  }
130
- function renderUpdateGroupsOnAppAsTable(updateGroups, { json }) {
125
+ function renderUpdateGroupsOnApp({ updateGroups, paginatedQueryOptions: { json }, }) {
131
126
  const updateGroupDescriptions = (0, utils_1.getUpdateGroupDescriptionsWithBranch)(updateGroups);
132
127
  if (json) {
133
128
  (0, json_1.printJsonOnlyOutput)({ currentPage: updateGroupDescriptions });
134
129
  }
135
- else {
136
- const updateGroupsTable = new cli_table3_1.default({
137
- head: utils_1.UPDATE_COLUMNS_WITH_BRANCH,
138
- wordWrap: true,
139
- });
140
- updateGroupDescriptions.forEach(({ branch, message, runtimeVersion, group, platforms }) => {
141
- updateGroupsTable.push([branch, message, runtimeVersion, group, platforms]);
142
- });
143
- log_1.default.addNewLineIfNone();
144
- log_1.default.log(chalk_1.default.bold('Recent update groups:'));
145
- log_1.default.addNewLineIfNone();
146
- log_1.default.log(updateGroupsTable.toString());
147
- }
130
+ log_1.default.addNewLineIfNone();
131
+ log_1.default.log(chalk_1.default.bold('Recent update groups:'));
132
+ log_1.default.newLine();
133
+ log_1.default.log(updateGroupDescriptions
134
+ .map(({ branch, ...update }) => (0, utils_1.formatBranch)({
135
+ branch,
136
+ update,
137
+ }))
138
+ .join(`\n\n${chalk_1.default.dim('———')}\n\n`));
148
139
  }
@@ -1,5 +1,5 @@
1
1
  import { ExpoConfig } from '@expo/config';
2
- import { Maybe, Robot, Update, UpdateFragment, User } from '../graphql/generated';
2
+ import { Maybe, Robot, Update, UpdateBranchFragment, UpdateFragment, User } from '../graphql/generated';
3
3
  import { RequestedPlatform } from '../platform';
4
4
  import { ProfileData } from '../utils/profiles';
5
5
  export declare type FormatUpdateParameter = Pick<Update, 'id' | 'createdAt' | 'message'> & {
@@ -17,12 +17,18 @@ export declare type FormattedUpdateGroupDescription = {
17
17
  platforms: string;
18
18
  runtimeVersion: string;
19
19
  };
20
+ export declare type FormattedBranchDescription = {
21
+ branch: string;
22
+ branchRolloutPercentage?: number;
23
+ update?: FormattedUpdateGroupDescription;
24
+ };
20
25
  export declare type FormattedUpdateGroupDescriptionWithBranch = FormattedUpdateGroupDescription & {
21
26
  branch: string;
22
27
  };
23
28
  export declare const UPDATE_COLUMNS: string[];
24
29
  export declare const UPDATE_COLUMNS_WITH_BRANCH: string[];
25
30
  export declare function formatUpdateGroup(update: FormattedUpdateGroupDescription): string;
31
+ export declare function formatBranch({ branch, branchRolloutPercentage, update, }: FormattedBranchDescription): string;
26
32
  export declare function getPlatformsForGroup({ group, updates, }: {
27
33
  group: string | undefined;
28
34
  updates: {
@@ -40,5 +46,6 @@ export declare function ensureValidVersions(exp: ExpoConfig, platform: Requested
40
46
  export declare function formatUpdateTitle(update: UpdateFragment): string;
41
47
  export declare function getUpdateGroupDescriptions(updateGroups: UpdateFragment[][]): FormattedUpdateGroupDescription[];
42
48
  export declare function getUpdateGroupDescriptionsWithBranch(updateGroups: UpdateFragment[][]): FormattedUpdateGroupDescriptionWithBranch[];
49
+ export declare function getBranchDescription(branch: UpdateBranchFragment): FormattedBranchDescription;
43
50
  export declare function checkEASUpdateURLIsSetAsync(exp: ExpoConfig, projectId: string): Promise<boolean>;
44
51
  export declare function validateBuildProfileConfigMatchesProjectConfigAsync(exp: ExpoConfig, buildProfile: ProfileData<'build'>, projectId: string, nonInteractive: boolean): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateBuildProfileConfigMatchesProjectConfigAsync = exports.checkEASUpdateURLIsSetAsync = exports.getUpdateGroupDescriptionsWithBranch = exports.getUpdateGroupDescriptions = exports.formatUpdateTitle = exports.ensureValidVersions = exports.formatUpdateMessage = exports.truncateString = exports.formatPlatformForUpdateGroup = exports.getPlatformsForGroup = exports.formatUpdateGroup = exports.UPDATE_COLUMNS_WITH_BRANCH = exports.UPDATE_COLUMNS = void 0;
3
+ exports.validateBuildProfileConfigMatchesProjectConfigAsync = exports.checkEASUpdateURLIsSetAsync = exports.getBranchDescription = exports.getUpdateGroupDescriptionsWithBranch = exports.getUpdateGroupDescriptions = exports.formatUpdateTitle = exports.ensureValidVersions = exports.formatUpdateMessage = exports.truncateString = exports.formatPlatformForUpdateGroup = exports.getPlatformsForGroup = exports.formatBranch = exports.formatUpdateGroup = exports.UPDATE_COLUMNS_WITH_BRANCH = exports.UPDATE_COLUMNS = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const timeago_js_1 = require("@expo/timeago.js");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
@@ -28,6 +28,21 @@ function formatUpdateGroup(update) {
28
28
  ]);
29
29
  }
30
30
  exports.formatUpdateGroup = formatUpdateGroup;
31
+ function formatBranch({ branch, branchRolloutPercentage, update, }) {
32
+ var _a, _b, _c, _d;
33
+ const rolloutField = branchRolloutPercentage
34
+ ? [{ label: 'Rollout', value: `${branchRolloutPercentage}%` }]
35
+ : [];
36
+ return (0, formatFields_1.default)([
37
+ { label: 'Branch', value: branch },
38
+ ...rolloutField,
39
+ { label: 'Platforms', value: (_a = update === null || update === void 0 ? void 0 : update.platforms) !== null && _a !== void 0 ? _a : 'N/A' },
40
+ { label: 'Runtime Version', value: (_b = update === null || update === void 0 ? void 0 : update.runtimeVersion) !== null && _b !== void 0 ? _b : 'N/A' },
41
+ { label: 'Message', value: (_c = update === null || update === void 0 ? void 0 : update.message) !== null && _c !== void 0 ? _c : 'N/A' },
42
+ { label: 'Group ID', value: (_d = update === null || update === void 0 ? void 0 : update.group) !== null && _d !== void 0 ? _d : 'N/A' },
43
+ ]);
44
+ }
45
+ exports.formatBranch = formatBranch;
31
46
  function getPlatformsForGroup({ group, updates = [], }) {
32
47
  const groupedUpdates = (0, groupBy_1.default)(updates, update => update.group);
33
48
  return formatPlatformForUpdateGroup(group ? groupedUpdates[group] : undefined);
@@ -110,6 +125,25 @@ function getUpdateGroupDescriptionsWithBranch(updateGroups) {
110
125
  }));
111
126
  }
112
127
  exports.getUpdateGroupDescriptionsWithBranch = getUpdateGroupDescriptionsWithBranch;
128
+ function getBranchDescription(branch) {
129
+ if (branch.updates.length === 0) {
130
+ return { branch: branch.name };
131
+ }
132
+ const latestUpdate = branch.updates[0];
133
+ return {
134
+ branch: branch.name,
135
+ update: {
136
+ message: formatUpdateMessage(latestUpdate),
137
+ runtimeVersion: latestUpdate.runtimeVersion,
138
+ group: latestUpdate.group,
139
+ platforms: getPlatformsForGroup({
140
+ group: latestUpdate.group,
141
+ updates: branch.updates,
142
+ }),
143
+ },
144
+ };
145
+ }
146
+ exports.getBranchDescription = getBranchDescription;
113
147
  async function checkEASUpdateURLIsSetAsync(exp, projectId) {
114
148
  var _a;
115
149
  const configuredURL = (_a = exp.updates) === null || _a === void 0 ? void 0 : _a.url;
@@ -0,0 +1,3 @@
1
+ import { BuildDistributionType } from '../build/types';
2
+ import { DistributionType } from '../graphql/generated';
3
+ export declare const buildDistributionTypeToGraphQLDistributionType: (buildDistribution?: BuildDistributionType) => DistributionType | undefined;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildDistributionTypeToGraphQLDistributionType = void 0;
4
+ const types_1 = require("../build/types");
5
+ const generated_1 = require("../graphql/generated");
6
+ const buildDistributionTypeToGraphQLDistributionType = (buildDistribution) => {
7
+ if (buildDistribution === types_1.BuildDistributionType.STORE) {
8
+ return generated_1.DistributionType.Store;
9
+ }
10
+ else if (buildDistribution === types_1.BuildDistributionType.INTERNAL) {
11
+ return generated_1.DistributionType.Internal;
12
+ }
13
+ else if (buildDistribution === types_1.BuildDistributionType.SIMULATOR) {
14
+ return generated_1.DistributionType.Simulator;
15
+ }
16
+ else {
17
+ return undefined;
18
+ }
19
+ };
20
+ exports.buildDistributionTypeToGraphQLDistributionType = buildDistributionTypeToGraphQLDistributionType;
@@ -0,0 +1,2 @@
1
+ export declare function downloadAndExtractAppAsync(url: string, applicationExtension: string): Promise<string>;
2
+ export declare function extractAppFromLocalArchiveAsync(appArchivePath: string, applicationExtension: string): Promise<string>;
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractAppFromLocalArchiveAsync = exports.downloadAndExtractAppAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
7
+ const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
8
+ const fs_1 = tslib_1.__importDefault(require("fs"));
9
+ const path_1 = tslib_1.__importDefault(require("path"));
10
+ const stream_1 = require("stream");
11
+ const tar_1 = require("tar");
12
+ const util_1 = require("util");
13
+ const uuid_1 = require("uuid");
14
+ const fetch_1 = tslib_1.__importDefault(require("../fetch"));
15
+ const log_1 = tslib_1.__importDefault(require("../log"));
16
+ const paths_1 = require("./paths");
17
+ const pipeline = (0, util_1.promisify)(stream_1.Stream.pipeline);
18
+ function wrapFetchWithProgress() {
19
+ return async (url, init, onProgressCallback) => {
20
+ const response = await (0, fetch_1.default)(url, init);
21
+ if (response.ok) {
22
+ const totalDownloadSize = response.headers.get('Content-Length');
23
+ const total = Number(totalDownloadSize);
24
+ if (!totalDownloadSize || isNaN(total) || total < 0) {
25
+ log_1.default.warn('Progress callback not supported for network request because "Content-Length" header missing or invalid in response from URL:', url.toString());
26
+ return response;
27
+ }
28
+ let length = 0;
29
+ const onProgress = (chunkLength) => {
30
+ if (chunkLength) {
31
+ length += chunkLength;
32
+ }
33
+ const progress = length / total;
34
+ onProgressCallback(progress, total, length);
35
+ };
36
+ response.body.on('data', chunk => {
37
+ onProgress(chunk.length);
38
+ });
39
+ response.body.on('end', () => {
40
+ onProgress();
41
+ });
42
+ }
43
+ return response;
44
+ };
45
+ }
46
+ async function downloadFileWithProgressBarAsync(url, outputPath, infoMessage) {
47
+ log_1.default.newLine();
48
+ log_1.default.log(infoMessage ? infoMessage : `Downloading file from ${url}...`);
49
+ const downloadProgressBar = new cli_progress_1.default.SingleBar({ format: '|{bar}|' }, cli_progress_1.default.Presets.rect);
50
+ let downloadProgressBarStarted = false;
51
+ const response = await wrapFetchWithProgress()(url, {
52
+ timeout: 1000 * 60 * 5, // 5 minutes
53
+ }, (_progress, total, loaded) => {
54
+ if (!downloadProgressBarStarted) {
55
+ downloadProgressBar.start(total, loaded);
56
+ downloadProgressBarStarted = true;
57
+ }
58
+ else if (loaded < total) {
59
+ downloadProgressBar.update(loaded);
60
+ }
61
+ else {
62
+ downloadProgressBar.stop();
63
+ }
64
+ });
65
+ if (!response.ok) {
66
+ throw new Error(`Failed to download file from ${url}`);
67
+ }
68
+ await pipeline(response.body, fs_1.default.createWriteStream(outputPath));
69
+ }
70
+ async function downloadAndExtractAppAsync(url, applicationExtension) {
71
+ const outputDir = path_1.default.join((0, paths_1.getTmpDirectory)(), (0, uuid_1.v4)());
72
+ await fs_1.default.promises.mkdir(outputDir, { recursive: true });
73
+ const tmpArchivePathDir = path_1.default.join((0, paths_1.getTmpDirectory)(), (0, uuid_1.v4)());
74
+ await fs_1.default.promises.mkdir(tmpArchivePathDir, { recursive: true });
75
+ const tmpArchivePath = path_1.default.join(tmpArchivePathDir, `${(0, uuid_1.v4)()}.tar.gz`);
76
+ await downloadFileWithProgressBarAsync(url, tmpArchivePath, 'Downloading app archive...');
77
+ await tarExtractAsync(tmpArchivePath, outputDir);
78
+ return await getAppPathAsync(outputDir, applicationExtension);
79
+ }
80
+ exports.downloadAndExtractAppAsync = downloadAndExtractAppAsync;
81
+ async function extractAppFromLocalArchiveAsync(appArchivePath, applicationExtension) {
82
+ const outputDir = path_1.default.join((0, paths_1.getTmpDirectory)(), (0, uuid_1.v4)());
83
+ await fs_1.default.promises.mkdir(outputDir, { recursive: true });
84
+ await tarExtractAsync(appArchivePath, outputDir);
85
+ return await getAppPathAsync(outputDir, applicationExtension);
86
+ }
87
+ exports.extractAppFromLocalArchiveAsync = extractAppFromLocalArchiveAsync;
88
+ async function getAppPathAsync(outputDir, applicationExtension) {
89
+ const appFileName = await (0, fast_glob_1.default)(`*.${applicationExtension}`, {
90
+ cwd: outputDir,
91
+ onlyFiles: false,
92
+ });
93
+ if (appFileName.length === 0) {
94
+ throw Error('Something went wrong while extracting the app from app archive');
95
+ }
96
+ return path_1.default.join(outputDir, appFileName[0]);
97
+ }
98
+ async function tarExtractAsync(input, output) {
99
+ try {
100
+ if (process.platform !== 'win32') {
101
+ await (0, spawn_async_1.default)('tar', ['-xf', input, '-C', output], {
102
+ stdio: 'inherit',
103
+ });
104
+ return;
105
+ }
106
+ }
107
+ catch (error) {
108
+ log_1.default.warn(`Failed to extract tar using native tools, falling back on JS tar module. ${error.message}`);
109
+ }
110
+ log_1.default.debug(`Extracting ${input} to ${output} using JS tar module`);
111
+ // tar node module has previously had problems with big files, and seems to
112
+ // be slower, so only use it as a backup.
113
+ await (0, tar_1.extract)({ file: input, cwd: output });
114
+ }