eas-cli 18.6.0 → 18.8.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 (43) hide show
  1. package/README.md +149 -91
  2. package/build/channel/insights/formatInsights.d.ts +47 -0
  3. package/build/channel/insights/formatInsights.js +108 -0
  4. package/build/commands/build/dev.d.ts +1 -0
  5. package/build/commands/build/dev.js +10 -2
  6. package/build/commands/channel/insights.d.ts +18 -0
  7. package/build/commands/channel/insights.js +71 -0
  8. package/build/commands/observe/events.d.ts +1 -0
  9. package/build/commands/observe/events.js +17 -4
  10. package/build/commands/observe/metrics.d.ts +1 -0
  11. package/build/commands/observe/metrics.js +18 -6
  12. package/build/commands/observe/versions.d.ts +1 -0
  13. package/build/commands/observe/versions.js +17 -4
  14. package/build/commands/update/insights.d.ts +19 -0
  15. package/build/commands/update/insights.js +75 -0
  16. package/build/commands/update/view.d.ts +4 -0
  17. package/build/commands/update/view.js +47 -2
  18. package/build/credentials/ios/appstore/capabilityIdentifiers.js +28 -3
  19. package/build/graphql/client.d.ts +13 -0
  20. package/build/graphql/client.js +36 -1
  21. package/build/graphql/generated.d.ts +193 -0
  22. package/build/graphql/generated.js +8 -2
  23. package/build/graphql/queries/ChannelInsightsQuery.d.ts +12 -0
  24. package/build/graphql/queries/ChannelInsightsQuery.js +81 -0
  25. package/build/graphql/queries/UpdateInsightsQuery.d.ts +10 -0
  26. package/build/graphql/queries/UpdateInsightsQuery.js +53 -0
  27. package/build/graphql/types/Observe.js +1 -0
  28. package/build/insights/formatTimespan.d.ts +7 -0
  29. package/build/insights/formatTimespan.js +15 -0
  30. package/build/insights/timeRange.d.ts +10 -0
  31. package/build/insights/timeRange.js +10 -0
  32. package/build/metadata/apple/tasks/previews.js +41 -15
  33. package/build/observe/formatEvents.d.ts +3 -0
  34. package/build/observe/formatEvents.js +4 -0
  35. package/build/observe/formatMetrics.d.ts +3 -2
  36. package/build/observe/formatMetrics.js +16 -27
  37. package/build/observe/formatVersions.js +2 -8
  38. package/build/update/insights/formatInsights.d.ts +34 -0
  39. package/build/update/insights/formatInsights.js +128 -0
  40. package/build/utils/renderTextTable.d.ts +6 -0
  41. package/build/utils/renderTextTable.js +23 -0
  42. package/oclif.manifest.json +773 -469
  43. package/package.json +5 -5
@@ -0,0 +1,47 @@
1
+ import { ChannelRuntimeInsights } from '../../graphql/queries/ChannelInsightsQuery';
2
+ export interface ChannelInsightsTimespan {
3
+ startTime: string;
4
+ endTime: string;
5
+ daysBack?: number;
6
+ }
7
+ export interface ChannelMostPopularUpdate {
8
+ rank: number;
9
+ groupId: string;
10
+ message: string | null;
11
+ platform: string;
12
+ totalUniqueUsers: number;
13
+ }
14
+ export interface ChannelInsightsSummary {
15
+ channelName: string;
16
+ runtimeVersion: string;
17
+ startTime: string;
18
+ endTime: string;
19
+ daysBack?: number;
20
+ embeddedUpdateTotalUniqueUsers: number;
21
+ otaTotalUniqueUsers: number;
22
+ mostPopularUpdates: ChannelMostPopularUpdate[];
23
+ cumulativeMetricsAtLastTimestamp: {
24
+ id: string;
25
+ label: string;
26
+ data: number;
27
+ }[];
28
+ uniqueUsersOverTime: {
29
+ labels: string[];
30
+ datasets: {
31
+ id: string;
32
+ label: string;
33
+ data: (number | null)[];
34
+ }[];
35
+ };
36
+ cumulativeMetricsOverTime: {
37
+ labels: string[];
38
+ datasets: {
39
+ id: string;
40
+ label: string;
41
+ data: (number | null)[];
42
+ }[];
43
+ };
44
+ }
45
+ export declare function toChannelInsightsSummary(channelName: string, runtimeVersion: string, insights: ChannelRuntimeInsights, timespan: ChannelInsightsTimespan): ChannelInsightsSummary;
46
+ export declare function buildChannelInsightsJson(summary: ChannelInsightsSummary): object;
47
+ export declare function buildChannelInsightsTable(summary: ChannelInsightsSummary): string;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toChannelInsightsSummary = toChannelInsightsSummary;
4
+ exports.buildChannelInsightsJson = buildChannelInsightsJson;
5
+ exports.buildChannelInsightsTable = buildChannelInsightsTable;
6
+ const tslib_1 = require("tslib");
7
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
+ const formatTimespan_1 = require("../../insights/formatTimespan");
9
+ const formatFields_1 = tslib_1.__importDefault(require("../../utils/formatFields"));
10
+ const renderTextTable_1 = tslib_1.__importDefault(require("../../utils/renderTextTable"));
11
+ function toChannelInsightsSummary(channelName, runtimeVersion, insights, timespan) {
12
+ const mostPopular = insights.mostPopularUpdates.map((u, i) => ({
13
+ rank: i + 1,
14
+ groupId: u.group,
15
+ message: u.message ?? null,
16
+ platform: u.platform,
17
+ totalUniqueUsers: u.insights.totalUniqueUsers,
18
+ }));
19
+ const otaTotalUniqueUsers = mostPopular.reduce((sum, u) => sum + u.totalUniqueUsers, 0);
20
+ return {
21
+ channelName,
22
+ runtimeVersion,
23
+ startTime: timespan.startTime,
24
+ endTime: timespan.endTime,
25
+ daysBack: timespan.daysBack,
26
+ embeddedUpdateTotalUniqueUsers: insights.embeddedUpdateTotalUniqueUsers,
27
+ otaTotalUniqueUsers,
28
+ mostPopularUpdates: mostPopular,
29
+ cumulativeMetricsAtLastTimestamp: insights.cumulativeMetricsOverTime.metricsAtLastTimestamp.map(m => ({ id: m.id, label: m.label, data: m.data })),
30
+ uniqueUsersOverTime: {
31
+ labels: insights.uniqueUsersOverTime.data.labels,
32
+ datasets: insights.uniqueUsersOverTime.data.datasets.map(d => ({
33
+ id: d.id,
34
+ label: d.label,
35
+ data: d.data,
36
+ })),
37
+ },
38
+ cumulativeMetricsOverTime: {
39
+ labels: insights.cumulativeMetricsOverTime.data.labels,
40
+ datasets: insights.cumulativeMetricsOverTime.data.datasets.map(d => ({
41
+ id: d.id,
42
+ label: d.label,
43
+ data: d.data,
44
+ })),
45
+ },
46
+ };
47
+ }
48
+ function buildChannelInsightsJson(summary) {
49
+ return {
50
+ channel: summary.channelName,
51
+ runtimeVersion: summary.runtimeVersion,
52
+ timespan: {
53
+ start: summary.startTime,
54
+ end: summary.endTime,
55
+ ...(summary.daysBack !== undefined ? { daysBack: summary.daysBack } : {}),
56
+ },
57
+ embeddedUpdateTotalUniqueUsers: summary.embeddedUpdateTotalUniqueUsers,
58
+ otaTotalUniqueUsers: summary.otaTotalUniqueUsers,
59
+ mostPopularUpdates: summary.mostPopularUpdates,
60
+ cumulativeMetricsAtLastTimestamp: summary.cumulativeMetricsAtLastTimestamp,
61
+ uniqueUsersOverTime: summary.uniqueUsersOverTime,
62
+ cumulativeMetricsOverTime: summary.cumulativeMetricsOverTime,
63
+ };
64
+ }
65
+ function buildChannelInsightsTable(summary) {
66
+ const sections = [];
67
+ sections.push(chalk_1.default.bold('Channel insights:'));
68
+ sections.push((0, formatFields_1.default)([
69
+ { label: 'Channel', value: summary.channelName },
70
+ { label: 'Runtime version', value: summary.runtimeVersion },
71
+ { label: 'Time range', value: (0, formatTimespan_1.formatTimespan)(summary) },
72
+ {
73
+ label: 'Embedded update users',
74
+ value: summary.embeddedUpdateTotalUniqueUsers.toLocaleString(),
75
+ },
76
+ { label: 'OTA update users', value: summary.otaTotalUniqueUsers.toLocaleString() },
77
+ ]));
78
+ if (summary.cumulativeMetricsAtLastTimestamp.length > 0) {
79
+ sections.push('');
80
+ sections.push(chalk_1.default.bold('Cumulative metrics at last timestamp:'));
81
+ sections.push((0, formatFields_1.default)(summary.cumulativeMetricsAtLastTimestamp.map(m => ({
82
+ label: m.label,
83
+ value: m.data.toLocaleString(),
84
+ }))));
85
+ }
86
+ if (summary.mostPopularUpdates.length > 0) {
87
+ sections.push('');
88
+ sections.push(chalk_1.default.bold(`Most popular updates${formatTrailingTimespan(summary)}:`));
89
+ sections.push(renderMostPopularTable(summary.mostPopularUpdates));
90
+ }
91
+ else {
92
+ sections.push('');
93
+ sections.push(chalk_1.default.yellow('No update launches recorded for this channel and runtime.'));
94
+ }
95
+ return sections.join('\n');
96
+ }
97
+ function formatTrailingTimespan(summary) {
98
+ return summary.daysBack ? ` (last ${summary.daysBack} days)` : '';
99
+ }
100
+ function renderMostPopularTable(rows) {
101
+ return (0, renderTextTable_1.default)(['#', 'Group ID', 'Platform', 'Unique users', 'Message'], rows.map(r => [
102
+ String(r.rank),
103
+ r.groupId,
104
+ r.platform,
105
+ r.totalUniqueUsers.toLocaleString(),
106
+ r.message ?? '',
107
+ ]));
108
+ }
@@ -7,6 +7,7 @@ export default class BuildDev extends EasCommand {
7
7
  platform: import("@oclif/core/lib/interfaces").OptionFlag<Platform | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
8
  profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
9
  'skip-build-if-not-found': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ 'skip-bundler': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
11
  };
11
12
  static contextDefinition: {
12
13
  projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
@@ -38,6 +38,10 @@ class BuildDev extends EasCommand_1.default {
38
38
  description: 'Skip build if no successful build with matching fingerprint is found.',
39
39
  default: false,
40
40
  }),
41
+ 'skip-bundler': core_1.Flags.boolean({
42
+ description: 'Install and run the development build without starting the bundler server.',
43
+ default: false,
44
+ }),
41
45
  };
42
46
  static contextDefinition = {
43
47
  ...this.ContextOptions.LoggedIn,
@@ -100,7 +104,9 @@ class BuildDev extends EasCommand_1.default {
100
104
  log_1.default.succeed(`🎯 Found successful build with matching fingerprint on EAS servers. Running it...`);
101
105
  if (build.artifacts?.applicationArchiveUrl) {
102
106
  await (0, runBuildAndSubmit_1.downloadAndRunAsync)(build);
103
- await this.startDevServerAsync({ projectDir, platform });
107
+ if (!flags['skip-bundler']) {
108
+ await this.startDevServerAsync({ projectDir, platform });
109
+ }
104
110
  return;
105
111
  }
106
112
  else {
@@ -143,7 +149,9 @@ class BuildDev extends EasCommand_1.default {
143
149
  downloadSimBuildAutoConfirm: true,
144
150
  envOverride: env,
145
151
  });
146
- await this.startDevServerAsync({ projectDir, platform });
152
+ if (!flags['skip-bundler']) {
153
+ await this.startDevServerAsync({ projectDir, platform });
154
+ }
147
155
  }
148
156
  async selectPlatformAsync(platform) {
149
157
  if (platform) {
@@ -0,0 +1,18 @@
1
+ import EasCommand from '../../commandUtils/EasCommand';
2
+ export default class ChannelInsights extends EasCommand {
3
+ static description: string;
4
+ static flags: {
5
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
6
+ 'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ channel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ 'runtime-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ days: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ start: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ end: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ };
13
+ static contextDefinition: {
14
+ loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
15
+ projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
16
+ };
17
+ runAsync(): Promise<void>;
18
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const formatInsights_1 = require("../../channel/insights/formatInsights");
6
+ const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
7
+ const flags_1 = require("../../commandUtils/flags");
8
+ const ChannelInsightsQuery_1 = require("../../graphql/queries/ChannelInsightsQuery");
9
+ const timeRange_1 = require("../../insights/timeRange");
10
+ const log_1 = tslib_1.__importDefault(require("../../log"));
11
+ const json_1 = require("../../utils/json");
12
+ class ChannelInsights extends EasCommand_1.default {
13
+ static description = 'display adoption, crash, and unique-user insights for a channel + runtime version';
14
+ static flags = {
15
+ channel: core_1.Flags.string({
16
+ description: 'Name of the channel.',
17
+ required: true,
18
+ }),
19
+ 'runtime-version': core_1.Flags.string({
20
+ description: 'Runtime version to query insights for.',
21
+ required: true,
22
+ }),
23
+ days: core_1.Flags.integer({
24
+ description: 'Show insights from the last N days (default 7, mutually exclusive with --start/--end).',
25
+ min: 1,
26
+ exclusive: ['start', 'end'],
27
+ }),
28
+ start: core_1.Flags.string({
29
+ description: 'Start of insights time range (ISO date).',
30
+ exclusive: ['days'],
31
+ }),
32
+ end: core_1.Flags.string({
33
+ description: 'End of insights time range (ISO date).',
34
+ exclusive: ['days'],
35
+ }),
36
+ ...flags_1.EasNonInteractiveAndJsonFlags,
37
+ };
38
+ static contextDefinition = {
39
+ ...this.ContextOptions.ProjectId,
40
+ ...this.ContextOptions.LoggedIn,
41
+ };
42
+ async runAsync() {
43
+ const { flags } = await this.parse(ChannelInsights);
44
+ const { json, nonInteractive } = (0, flags_1.resolveNonInteractiveAndJsonFlags)(flags);
45
+ const { projectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(ChannelInsights, { nonInteractive });
46
+ if (json) {
47
+ (0, json_1.enableJsonOutput)();
48
+ }
49
+ const { daysBack, startTime, endTime } = (0, timeRange_1.resolveInsightsTimeRange)(flags);
50
+ const insights = await ChannelInsightsQuery_1.ChannelInsightsQuery.viewChannelRuntimeInsightsAsync(graphqlClient, {
51
+ appId: projectId,
52
+ channelName: flags.channel,
53
+ runtimeVersion: flags['runtime-version'],
54
+ startTime,
55
+ endTime,
56
+ });
57
+ const summary = (0, formatInsights_1.toChannelInsightsSummary)(flags.channel, flags['runtime-version'], insights, {
58
+ startTime,
59
+ endTime,
60
+ daysBack,
61
+ });
62
+ if (json) {
63
+ (0, json_1.printJsonOnlyOutput)((0, formatInsights_1.buildChannelInsightsJson)(summary));
64
+ }
65
+ else {
66
+ log_1.default.addNewLineIfNone();
67
+ log_1.default.log((0, formatInsights_1.buildChannelInsightsTable)(summary));
68
+ }
69
+ }
70
+ }
71
+ exports.default = ChannelInsights;
@@ -23,5 +23,6 @@ export default class ObserveEvents extends EasCommand {
23
23
  loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
24
24
  projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
25
25
  };
26
+ private static loggedInOnlyContextDefinition;
26
27
  runAsync(): Promise<void>;
27
28
  }
@@ -71,12 +71,25 @@ class ObserveEvents extends EasCommand_1.default {
71
71
  ...this.ContextOptions.ProjectId,
72
72
  ...this.ContextOptions.LoggedIn,
73
73
  };
74
+ static loggedInOnlyContextDefinition = {
75
+ ...this.ContextOptions.LoggedIn,
76
+ };
74
77
  async runAsync() {
75
78
  const { flags, args } = await this.parse(ObserveEvents);
76
- const { projectId: contextProjectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(ObserveEvents, {
77
- nonInteractive: flags['non-interactive'],
78
- });
79
- const projectId = flags['project-id'] ?? contextProjectId;
79
+ let projectId;
80
+ let graphqlClient;
81
+ if (flags['project-id']) {
82
+ projectId = flags['project-id'];
83
+ const ctx = await this.getContextAsync({ contextDefinition: ObserveEvents.loggedInOnlyContextDefinition }, { nonInteractive: flags['non-interactive'] });
84
+ graphqlClient = ctx.loggedIn.graphqlClient;
85
+ }
86
+ else {
87
+ const ctx = await this.getContextAsync(ObserveEvents, {
88
+ nonInteractive: flags['non-interactive'],
89
+ });
90
+ projectId = ctx.projectId;
91
+ graphqlClient = ctx.loggedIn.graphqlClient;
92
+ }
80
93
  if (flags.json) {
81
94
  (0, json_1.enableJsonOutput)();
82
95
  }
@@ -17,5 +17,6 @@ export default class ObserveMetrics extends EasCommand {
17
17
  loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
18
18
  projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
19
19
  };
20
+ private static loggedInOnlyContextDefinition;
20
21
  runAsync(): Promise<void>;
21
22
  }
@@ -69,12 +69,25 @@ class ObserveMetrics extends EasCommand_1.default {
69
69
  ...this.ContextOptions.ProjectId,
70
70
  ...this.ContextOptions.LoggedIn,
71
71
  };
72
+ static loggedInOnlyContextDefinition = {
73
+ ...this.ContextOptions.LoggedIn,
74
+ };
72
75
  async runAsync() {
73
76
  const { flags } = await this.parse(ObserveMetrics);
74
- const { projectId: contextProjectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(ObserveMetrics, {
75
- nonInteractive: flags['non-interactive'],
76
- });
77
- const projectId = flags['project-id'] ?? contextProjectId;
77
+ let projectId;
78
+ let graphqlClient;
79
+ if (flags['project-id']) {
80
+ projectId = flags['project-id'];
81
+ const ctx = await this.getContextAsync({ contextDefinition: ObserveMetrics.loggedInOnlyContextDefinition }, { nonInteractive: flags['non-interactive'] });
82
+ graphqlClient = ctx.loggedIn.graphqlClient;
83
+ }
84
+ else {
85
+ const ctx = await this.getContextAsync(ObserveMetrics, {
86
+ nonInteractive: flags['non-interactive'],
87
+ });
88
+ projectId = ctx.projectId;
89
+ graphqlClient = ctx.loggedIn.graphqlClient;
90
+ }
78
91
  if (flags.json) {
79
92
  (0, json_1.enableJsonOutput)();
80
93
  }
@@ -94,7 +107,7 @@ class ObserveMetrics extends EasCommand_1.default {
94
107
  : undefined;
95
108
  if (flags.json) {
96
109
  const stats = argumentsStat ?? DEFAULT_STATS_JSON;
97
- (0, json_1.printJsonOnlyOutput)((0, formatMetrics_1.buildObserveMetricsJson)(metricsMap, metricNames, stats, totalEventCounts));
110
+ (0, json_1.printJsonOnlyOutput)((0, formatMetrics_1.buildObserveMetricsJson)(metricsMap, metricNames, stats, totalEventCounts, buildNumbersMap, updateIdsMap));
98
111
  }
99
112
  else {
100
113
  const stats = argumentsStat ?? DEFAULT_STATS_TABLE;
@@ -102,7 +115,6 @@ class ObserveMetrics extends EasCommand_1.default {
102
115
  log_1.default.log((0, formatMetrics_1.buildObserveMetricsTable)(metricsMap, metricNames, stats, {
103
116
  daysBack,
104
117
  buildNumbersMap,
105
- updateIdsMap,
106
118
  totalEventCounts,
107
119
  }));
108
120
  }
@@ -15,5 +15,6 @@ export default class ObserveVersions extends EasCommand {
15
15
  loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
16
16
  projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
17
17
  };
18
+ private static loggedInOnlyContextDefinition;
18
19
  runAsync(): Promise<void>;
19
20
  }
@@ -40,12 +40,25 @@ class ObserveVersions extends EasCommand_1.default {
40
40
  ...this.ContextOptions.ProjectId,
41
41
  ...this.ContextOptions.LoggedIn,
42
42
  };
43
+ static loggedInOnlyContextDefinition = {
44
+ ...this.ContextOptions.LoggedIn,
45
+ };
43
46
  async runAsync() {
44
47
  const { flags } = await this.parse(ObserveVersions);
45
- const { projectId: contextProjectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(ObserveVersions, {
46
- nonInteractive: flags['non-interactive'],
47
- });
48
- const projectId = flags['project-id'] ?? contextProjectId;
48
+ let projectId;
49
+ let graphqlClient;
50
+ if (flags['project-id']) {
51
+ projectId = flags['project-id'];
52
+ const ctx = await this.getContextAsync({ contextDefinition: ObserveVersions.loggedInOnlyContextDefinition }, { nonInteractive: flags['non-interactive'] });
53
+ graphqlClient = ctx.loggedIn.graphqlClient;
54
+ }
55
+ else {
56
+ const ctx = await this.getContextAsync(ObserveVersions, {
57
+ nonInteractive: flags['non-interactive'],
58
+ });
59
+ projectId = ctx.projectId;
60
+ graphqlClient = ctx.loggedIn.graphqlClient;
61
+ }
49
62
  if (flags.json) {
50
63
  (0, json_1.enableJsonOutput)();
51
64
  }
@@ -0,0 +1,19 @@
1
+ import EasCommand from '../../commandUtils/EasCommand';
2
+ export default class UpdateInsights extends EasCommand {
3
+ static description: string;
4
+ static args: {
5
+ groupId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ 'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ platform: import("@oclif/core/lib/interfaces").OptionFlag<"android" | "ios" | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ days: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ start: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ end: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ };
15
+ static contextDefinition: {
16
+ loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
17
+ };
18
+ runAsync(): Promise<void>;
19
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
6
+ const flags_1 = require("../../commandUtils/flags");
7
+ const UpdateInsightsQuery_1 = require("../../graphql/queries/UpdateInsightsQuery");
8
+ const timeRange_1 = require("../../insights/timeRange");
9
+ const log_1 = tslib_1.__importDefault(require("../../log"));
10
+ const formatInsights_1 = require("../../update/insights/formatInsights");
11
+ const json_1 = require("../../utils/json");
12
+ class UpdateInsights extends EasCommand_1.default {
13
+ static description = 'display launch, crash, unique-user, and size insights for an update group';
14
+ static args = {
15
+ groupId: core_1.Args.string({
16
+ required: true,
17
+ description: 'The ID of an update group.',
18
+ }),
19
+ };
20
+ static flags = {
21
+ platform: core_1.Flags.option({
22
+ description: 'Filter to a single platform.',
23
+ options: ['ios', 'android'],
24
+ })(),
25
+ days: core_1.Flags.integer({
26
+ description: `Show insights from the last N days (default ${timeRange_1.INSIGHTS_DEFAULT_DAYS_BACK}, mutually exclusive with --start/--end).`,
27
+ min: 1,
28
+ exclusive: ['start', 'end'],
29
+ }),
30
+ start: core_1.Flags.string({
31
+ description: 'Start of insights time range (ISO date).',
32
+ exclusive: ['days'],
33
+ }),
34
+ end: core_1.Flags.string({
35
+ description: 'End of insights time range (ISO date).',
36
+ exclusive: ['days'],
37
+ }),
38
+ ...flags_1.EasNonInteractiveAndJsonFlags,
39
+ };
40
+ static contextDefinition = {
41
+ ...this.ContextOptions.LoggedIn,
42
+ };
43
+ async runAsync() {
44
+ const { args: { groupId }, flags, } = await this.parse(UpdateInsights);
45
+ const { json, nonInteractive } = (0, flags_1.resolveNonInteractiveAndJsonFlags)(flags);
46
+ const { loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateInsights, { nonInteractive });
47
+ if (json) {
48
+ (0, json_1.enableJsonOutput)();
49
+ }
50
+ const { daysBack, startTime, endTime } = (0, timeRange_1.resolveInsightsTimeRange)(flags);
51
+ const allUpdates = await UpdateInsightsQuery_1.UpdateInsightsQuery.viewUpdateGroupInsightsAsync(graphqlClient, {
52
+ groupId,
53
+ startTime,
54
+ endTime,
55
+ });
56
+ const updates = flags.platform
57
+ ? allUpdates.filter(u => u.platform === flags.platform)
58
+ : allUpdates;
59
+ if (updates.length === 0) {
60
+ throw new Error(`Update group "${groupId}" has no ${flags.platform} update (available platforms: ${allUpdates
61
+ .map(u => u.platform)
62
+ .sort()
63
+ .join(', ')}).`);
64
+ }
65
+ const summary = (0, formatInsights_1.toUpdateInsightsSummary)(groupId, updates, { startTime, endTime, daysBack });
66
+ if (json) {
67
+ (0, json_1.printJsonOnlyOutput)((0, formatInsights_1.buildUpdateInsightsJson)(summary));
68
+ }
69
+ else {
70
+ log_1.default.addNewLineIfNone();
71
+ log_1.default.log((0, formatInsights_1.buildUpdateInsightsTable)(summary));
72
+ }
73
+ }
74
+ }
75
+ exports.default = UpdateInsights;
@@ -6,6 +6,10 @@ export default class UpdateView extends EasCommand {
6
6
  };
7
7
  static flags: {
8
8
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ insights: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ days: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ start: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ end: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
13
  };
10
14
  static contextDefinition: {
11
15
  loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
@@ -5,8 +5,11 @@ const core_1 = require("@oclif/core");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
6
  const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
7
7
  const flags_1 = require("../../commandUtils/flags");
8
+ const UpdateInsightsQuery_1 = require("../../graphql/queries/UpdateInsightsQuery");
8
9
  const UpdateQuery_1 = require("../../graphql/queries/UpdateQuery");
10
+ const timeRange_1 = require("../../insights/timeRange");
9
11
  const log_1 = tslib_1.__importDefault(require("../../log"));
12
+ const formatInsights_1 = require("../../update/insights/formatInsights");
10
13
  const utils_1 = require("../../update/utils");
11
14
  const json_1 = require("../../utils/json");
12
15
  class UpdateView extends EasCommand_1.default {
@@ -18,25 +21,67 @@ class UpdateView extends EasCommand_1.default {
18
21
  }),
19
22
  };
20
23
  static flags = {
24
+ insights: core_1.Flags.boolean({
25
+ description: 'Also show insights (launches, crash rate, unique users, payload size) for the update group.',
26
+ default: false,
27
+ }),
28
+ days: core_1.Flags.integer({
29
+ description: 'Show insights from the last N days (default 7). Only used with --insights.',
30
+ min: 1,
31
+ exclusive: ['start', 'end'],
32
+ }),
33
+ start: core_1.Flags.string({
34
+ description: 'Start of insights time range (ISO date). Only used with --insights.',
35
+ exclusive: ['days'],
36
+ }),
37
+ end: core_1.Flags.string({
38
+ description: 'End of insights time range (ISO date). Only used with --insights.',
39
+ exclusive: ['days'],
40
+ }),
21
41
  ...flags_1.EasJsonOnlyFlag,
22
42
  };
23
43
  static contextDefinition = {
24
44
  ...this.ContextOptions.LoggedIn,
25
45
  };
26
46
  async runAsync() {
27
- const { args: { groupId }, flags: { json: jsonFlag }, } = await this.parse(UpdateView);
47
+ const { args: { groupId }, flags: { json: jsonFlag, insights: insightsFlag, days, start, end }, } = await this.parse(UpdateView);
48
+ if (!insightsFlag && (days !== undefined || start !== undefined || end !== undefined)) {
49
+ throw new Error('--days, --start, and --end can only be used with --insights.');
50
+ }
28
51
  const { loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateView, { nonInteractive: true });
29
52
  if (jsonFlag) {
30
53
  (0, json_1.enableJsonOutput)();
31
54
  }
32
55
  const updatesByGroup = await UpdateQuery_1.UpdateQuery.viewUpdateGroupAsync(graphqlClient, { groupId });
56
+ let insightsSummary = null;
57
+ if (insightsFlag) {
58
+ const { daysBack, startTime, endTime } = (0, timeRange_1.resolveInsightsTimeRange)({ days, start, end });
59
+ const updatesWithInsights = await UpdateInsightsQuery_1.UpdateInsightsQuery.viewUpdateGroupInsightsAsync(graphqlClient, { groupId, startTime, endTime });
60
+ insightsSummary = (0, formatInsights_1.toUpdateInsightsSummary)(groupId, updatesWithInsights, {
61
+ startTime,
62
+ endTime,
63
+ daysBack,
64
+ });
65
+ }
33
66
  if (jsonFlag) {
34
- (0, json_1.printJsonOnlyOutput)((0, utils_1.getUpdateJsonInfosForUpdates)(updatesByGroup));
67
+ if (insightsSummary) {
68
+ (0, json_1.printJsonOnlyOutput)({
69
+ updates: (0, utils_1.getUpdateJsonInfosForUpdates)(updatesByGroup),
70
+ insights: (0, formatInsights_1.buildUpdateInsightsJson)(insightsSummary),
71
+ });
72
+ }
73
+ else {
74
+ (0, json_1.printJsonOnlyOutput)((0, utils_1.getUpdateJsonInfosForUpdates)(updatesByGroup));
75
+ }
35
76
  }
36
77
  else {
37
78
  const [updateGroupDescription] = (0, utils_1.getUpdateGroupDescriptions)([updatesByGroup]);
38
79
  log_1.default.log(chalk_1.default.bold('Update group:'));
39
80
  log_1.default.log((0, utils_1.formatUpdateGroup)(updateGroupDescription));
81
+ if (insightsSummary) {
82
+ log_1.default.addNewLineIfNone();
83
+ log_1.default.log((0, formatInsights_1.buildUpdateInsightsTable)(insightsSummary));
84
+ }
40
85
  }
41
86
  }
42
87
  }