Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ This is the log of notable changes to EAS CLI and related packages.
- [build-tools] Add composable custom build functions for downloading, installing, and launching application archives in simulator sessions. ([#4222](https://github.com/expo/eas-cli/pull/4222) by [@szdziedzic](https://github.com/szdziedzic))
- [eas-cli] Add `--build-id`, `--application-archive-url`, and `--expo-go` to `eas simulator` to install and launch an application before the session is ready. ([#4223](https://github.com/expo/eas-cli/pull/4223) by [@szdziedzic](https://github.com/szdziedzic))
- [eas-cli] Add `--environment` flag to the `eas observe:*` commands. ([#4275](https://github.com/expo/eas-cli/pull/4275) by [@kadikraman](https://github.com/kadikraman))
- [eas-cli] Add `apple` value to the `--platform` flag of the `eas observe:*` commands. ([#4276](https://github.com/expo/eas-cli/pull/4276) by [@kadikraman](https://github.com/kadikraman))

### 🐛 Bug fixes

Expand Down
22 changes: 18 additions & 4 deletions packages/eas-cli/src/commands/observe/__tests__/events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ describe(ObserveEvents, () => {
appId: projectId,
startTime: '2025-06-08T12:00:00.000Z',
endTime: '2025-06-15T12:00:00.000Z',
platform: AppObservePlatform.Ios,
platforms: [AppObservePlatform.Ios],
environment: undefined,
});

jest.useRealTimers();
Expand Down Expand Up @@ -250,7 +251,20 @@ describe(ObserveEvents, () => {
await command.runAsync();

const options = mockFetchObserveCustomEventsAsync.mock.calls[0][2];
expect(options.platform).toBe(AppObservePlatform.Ios);
expect(options.platforms).toEqual([AppObservePlatform.Ios]);
});

it('passes --platform apple as every Apple platform', async () => {
const command = createCommand(['my_event', '--platform', 'apple']);
await command.runAsync();

const options = mockFetchObserveCustomEventsAsync.mock.calls[0][2];
expect(options.platforms).toEqual([
AppObservePlatform.Ios,
AppObservePlatform.Ipados,
AppObservePlatform.Tvos,
AppObservePlatform.Macos,
]);
});

it('passes --app-version', async () => {
Expand All @@ -277,12 +291,12 @@ describe(ObserveEvents, () => {
expect(options.sessionId).toBe('session-xyz');
});

it('does not pass platform, appVersion, updateId, or sessionId when flags are not provided', async () => {
it('does not pass platforms, appVersion, updateId, or sessionId when flags are not provided', async () => {
const command = createCommand(['my_event']);
await command.runAsync();

const options = mockFetchObserveCustomEventsAsync.mock.calls[0][2];
expect(options.platform).toBeUndefined();
expect(options.platforms).toBeUndefined();
expect(options.appVersion).toBeUndefined();
expect(options.updateId).toBeUndefined();
expect(options.sessionId).toBeUndefined();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { GraphQLError } from 'graphql';

import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { getMockOclifConfig } from '../../../__tests__/commands/utils';
import { AppPlatform } from '../../../graphql/generated';
import { AppObservePlatform } from '../../../graphql/generated';
import { fetchObserveMetricsAsync, validateDateFlag } from '../../../observe/fetchMetrics';
import { EAS_OBSERVE_FEATURE_NOT_AVAILABLE_IN_FREE_TIER_ERROR_CODE } from '../../../observe/planGating';
import { buildObserveMetricsJson, buildObserveMetricsTable } from '../../../observe/formatMetrics';
import { enableJsonOutput, printJsonOnlyOutput } from '../../../utils/json';
import { ObservePlatformTarget } from '../../../observe/platforms';
import ObserveMetricsSummary from '../metrics-summary';

jest.mock('../../../observe/fetchMetrics', () => {
Expand All @@ -31,6 +32,10 @@ const mockBuildObserveMetricsSummaryJson = jest.mocked(buildObserveMetricsJson);
const mockEnableJsonOutput = jest.mocked(enableJsonOutput);
const mockPrintJsonOnlyOutput = jest.mocked(printJsonOnlyOutput);

function target(platform: AppObservePlatform): ObservePlatformTarget {
return { key: platform, platforms: [platform] };
}

describe(ObserveMetricsSummary, () => {
const graphqlClient = {} as any as ExpoGraphqlClient;
const mockConfig = getMockOclifConfig();
Expand Down Expand Up @@ -83,7 +88,7 @@ describe(ObserveMetricsSummary, () => {

expect(mockFetchObserveMetricsSummaryAsync).toHaveBeenCalledTimes(1);
const platforms = mockFetchObserveMetricsSummaryAsync.mock.calls[0][3];
expect(platforms).toEqual([AppPlatform.Android, AppPlatform.Ios]);
expect(platforms).toEqual([target(AppObservePlatform.Android), target(AppObservePlatform.Ios)]);

jest.useRealTimers();
});
Expand All @@ -93,15 +98,41 @@ describe(ObserveMetricsSummary, () => {
await command.runAsync();

const platforms = mockFetchObserveMetricsSummaryAsync.mock.calls[0][3];
expect(platforms).toEqual([AppPlatform.Android]);
expect(platforms).toEqual([target(AppObservePlatform.Android)]);
});

it('queries only iOS when --platform ios is passed', async () => {
const command = createCommand(['--platform', 'ios']);
await command.runAsync();

const platforms = mockFetchObserveMetricsSummaryAsync.mock.calls[0][3];
expect(platforms).toEqual([AppPlatform.Ios]);
expect(platforms).toEqual([target(AppObservePlatform.Ios)]);
});

it('queries one combined target covering every Apple platform when --platform apple is passed', async () => {
const command = createCommand(['--platform', 'apple']);
await command.runAsync();

const platforms = mockFetchObserveMetricsSummaryAsync.mock.calls[0][3];
expect(platforms).toEqual([
{
key: 'APPLE',
platforms: [
AppObservePlatform.Ios,
AppObservePlatform.Ipados,
AppObservePlatform.Tvos,
AppObservePlatform.Macos,
],
},
]);
});

it('queries only macOS when --platform macos is passed', async () => {
const command = createCommand(['--platform', 'macos']);
await command.runAsync();

const platforms = mockFetchObserveMetricsSummaryAsync.mock.calls[0][3];
expect(platforms).toEqual([target(AppObservePlatform.Macos)]);
});

it('passes --environment through to fetchObserveMetricsAsync', async () => {
Expand Down
12 changes: 6 additions & 6 deletions packages/eas-cli/src/commands/observe/__tests__/metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,20 @@ describe(ObserveMetrics, () => {
await expect(command.runAsync()).rejects.toThrow();
});

it('passes --platform ios to fetchObserveEventsAsync as AppObservePlatform.Ios', async () => {
it('passes --platform ios to fetchObserveEventsAsync', async () => {
const command = createCommand(['tti', '--platform', 'ios']);
await command.runAsync();

const options = mockFetchObserveEventsAsync.mock.calls[0][2];
expect(options.platform).toBe(AppObservePlatform.Ios);
expect(options.platforms).toEqual([AppObservePlatform.Ios]);
});

it('passes --platform android to fetchObserveEventsAsync as AppObservePlatform.Android', async () => {
it('passes --platform android to fetchObserveEventsAsync', async () => {
const command = createCommand(['tti', '--platform', 'android']);
await command.runAsync();

const options = mockFetchObserveEventsAsync.mock.calls[0][2];
expect(options.platform).toBe(AppObservePlatform.Android);
expect(options.platforms).toEqual([AppObservePlatform.Android]);
});

it('passes --app-version to fetchObserveEventsAsync', async () => {
Expand All @@ -225,12 +225,12 @@ describe(ObserveMetrics, () => {
expect(options.updateId).toBe('update-xyz');
});

it('does not pass platform, appVersion, or updateId when flags are not provided', async () => {
it('does not pass platforms, appVersion, or updateId when flags are not provided', async () => {
const command = createCommand(['tti']);
await command.runAsync();

const options = mockFetchObserveEventsAsync.mock.calls[0][2];
expect(options.platform).toBeUndefined();
expect(options.platforms).toBeUndefined();
expect(options.appVersion).toBeUndefined();
expect(options.updateId).toBeUndefined();
});
Expand Down
14 changes: 11 additions & 3 deletions packages/eas-cli/src/commands/observe/__tests__/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { GraphQLError } from 'graphql';

import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { getMockOclifConfig } from '../../../__tests__/commands/utils';
import { AppPlatform } from '../../../graphql/generated';
import { AppObservePlatform } from '../../../graphql/generated';
import { fetchObserveNavigationRoutesAsync } from '../../../observe/fetchNavigationRoutes';
import { EAS_OBSERVE_FEATURE_NOT_AVAILABLE_IN_FREE_TIER_ERROR_CODE } from '../../../observe/planGating';
import {
buildObserveNavigationRoutesJson,
buildObserveNavigationRoutesTable,
} from '../../../observe/formatNavigationRoutes';
import { enableJsonOutput, printJsonOnlyOutput } from '../../../utils/json';
import { ObservePlatformTarget } from '../../../observe/platforms';
import ObserveRoutes from '../routes';

jest.mock('../../../observe/fetchNavigationRoutes');
Expand All @@ -31,6 +32,10 @@ const mockBuildObserveNavigationRoutesJson = jest.mocked(buildObserveNavigationR
const mockEnableJsonOutput = jest.mocked(enableJsonOutput);
const mockPrintJsonOnlyOutput = jest.mocked(printJsonOnlyOutput);

function target(platform: AppObservePlatform): ObservePlatformTarget {
return { key: platform, platforms: [platform] };
}

describe(ObserveRoutes, () => {
const graphqlClient = {} as any as ExpoGraphqlClient;
const mockConfig = getMockOclifConfig();
Expand Down Expand Up @@ -78,7 +83,10 @@ describe(ObserveRoutes, () => {

expect(mockFetchObserveNavigationRoutesAsync).toHaveBeenCalledTimes(1);
const options = mockFetchObserveNavigationRoutesAsync.mock.calls[0][2];
expect(options.platforms).toEqual([AppPlatform.Android, AppPlatform.Ios]);
expect(options.targets).toEqual([
target(AppObservePlatform.Android),
target(AppObservePlatform.Ios),
]);
expect(options.limit).toBe(50);

const tableCall = mockBuildObserveNavigationRoutesTable.mock.calls[0];
Expand All @@ -95,7 +103,7 @@ describe(ObserveRoutes, () => {
await command.runAsync();

const options = mockFetchObserveNavigationRoutesAsync.mock.calls[0][2];
expect(options.platforms).toEqual([AppPlatform.Ios]);
expect(options.targets).toEqual([target(AppObservePlatform.Ios)]);
});

it('resolves --metric short aliases to navigation metric full names and deduplicates', async () => {
Expand Down
15 changes: 10 additions & 5 deletions packages/eas-cli/src/commands/observe/__tests__/versions.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { getMockOclifConfig } from '../../../__tests__/commands/utils';
import { AppPlatform } from '../../../graphql/generated';
import { AppObservePlatform } from '../../../graphql/generated';
import { fetchObserveVersionsAsync } from '../../../observe/fetchVersions';
import {
buildObserveVersionsJson,
buildObserveVersionsTable,
} from '../../../observe/formatVersions';
import { enableJsonOutput, printJsonOnlyOutput } from '../../../utils/json';
import { ObservePlatformTarget } from '../../../observe/platforms';
import ObserveVersions from '../versions';

jest.mock('../../../observe/fetchVersions');
Expand All @@ -23,6 +24,10 @@ const mockBuildObserveVersionsJson = jest.mocked(buildObserveVersionsJson);
const mockEnableJsonOutput = jest.mocked(enableJsonOutput);
const mockPrintJsonOnlyOutput = jest.mocked(printJsonOnlyOutput);

function target(platform: AppObservePlatform): ObservePlatformTarget {
return { key: platform, platforms: [platform] };
}

describe(ObserveVersions, () => {
const graphqlClient = {} as any as ExpoGraphqlClient;
const mockConfig = getMockOclifConfig();
Expand Down Expand Up @@ -52,7 +57,7 @@ describe(ObserveVersions, () => {

expect(mockFetchObserveVersionsAsync).toHaveBeenCalledTimes(1);
const platforms = mockFetchObserveVersionsAsync.mock.calls[0][2];
expect(platforms).toEqual([AppPlatform.Android, AppPlatform.Ios]);
expect(platforms).toEqual([target(AppObservePlatform.Android), target(AppObservePlatform.Ios)]);

jest.useRealTimers();
});
Expand All @@ -62,15 +67,15 @@ describe(ObserveVersions, () => {
await command.runAsync();

const platforms = mockFetchObserveVersionsAsync.mock.calls[0][2];
expect(platforms).toEqual([AppPlatform.Android]);
expect(platforms).toEqual([target(AppObservePlatform.Android)]);
});

it('queries only iOS when --platform ios is passed', async () => {
const command = createCommand(['--platform', 'ios']);
await command.runAsync();

const platforms = mockFetchObserveVersionsAsync.mock.calls[0][2];
expect(platforms).toEqual([AppPlatform.Ios]);
expect(platforms).toEqual([target(AppObservePlatform.Ios)]);
});

it('passes --environment through to fetchObserveVersionsAsync', async () => {
Expand Down Expand Up @@ -171,7 +176,7 @@ describe(ObserveVersions, () => {
it('calls enableJsonOutput and printJsonOnlyOutput when --json is provided', async () => {
mockFetchObserveVersionsAsync.mockResolvedValue([
{
platform: AppPlatform.Ios,
platform: AppObservePlatform.Ios,
appVersions: [
{
appVersion: '1.0.0',
Expand Down
10 changes: 5 additions & 5 deletions packages/eas-cli/src/commands/observe/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
buildObserveCustomEventsTable,
} from '../../observe/formatCustomEvents';
import { withObservePlanGateHandlingAsync } from '../../observe/planGating';
import { appObservePlatformFromFlag } from '../../observe/platforms';
import { observePlatformsFromFlag } from '../../observe/platforms';
import { resolveObserveCommandContextAsync } from '../../observe/resolveProjectContext';
import { resolveTimeRange } from '../../observe/startAndEndTime';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
Expand Down Expand Up @@ -102,7 +102,7 @@ export default class ObserveEvents extends EasCommand {

const { daysBack, startTime, endTime } = resolveTimeRange(flags);

const platform = appObservePlatformFromFlag(flags.platform);
const platforms = observePlatformsFromFlag(flags.platform);

// A session ID narrows to a single session, so show that session's events
// (like --all-events) instead of the account-wide name+count summary, which
Expand All @@ -113,7 +113,7 @@ export default class ObserveEvents extends EasCommand {
appId: projectId,
startTime,
endTime,
platform,
platforms,
environment: flags.environment,
})
);
Expand Down Expand Up @@ -141,7 +141,7 @@ export default class ObserveEvents extends EasCommand {
...(flags.after && { after: flags.after }),
startTime,
endTime,
platform,
platforms,
appVersion: flags['app-version'],
updateId: flags['update-id'],
sessionId: flags['session-id'],
Expand All @@ -154,7 +154,7 @@ export default class ObserveEvents extends EasCommand {
appId: projectId,
startTime,
endTime,
platform,
platforms,
environment: flags.environment,
});

Expand Down
6 changes: 3 additions & 3 deletions packages/eas-cli/src/commands/observe/metrics-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '../../observe/formatMetrics';
import { METRIC_ALIASES, resolveMetricName } from '../../observe/metricNames';
import { withObservePlanGateHandlingAsync } from '../../observe/planGating';
import { appPlatformsFromFlag } from '../../observe/platforms';
import { observePlatformTargetsFromFlag } from '../../observe/platforms';
import { resolveObserveCommandContextAsync } from '../../observe/resolveProjectContext';
import { resolveTimeRange } from '../../observe/startAndEndTime';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
Expand Down Expand Up @@ -99,15 +99,15 @@ export default class ObserveMetricsSummary extends EasCommand {

const { daysBack, startTime, endTime } = resolveTimeRange(flags);

const platforms = appPlatformsFromFlag(flags.platform);
const targets = observePlatformTargetsFromFlag(flags.platform);

const { metricsMap, buildNumbersMap, updateIdsMap, totalEventCounts } =
await withObservePlanGateHandlingAsync(() =>
fetchObserveMetricsAsync(
graphqlClient,
projectId,
metricNames,
platforms,
targets,
startTime,
endTime,
flags.environment
Expand Down
10 changes: 5 additions & 5 deletions packages/eas-cli/src/commands/observe/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
import { METRIC_ALIASES, METRIC_SHORT_NAMES, resolveMetricName } from '../../observe/metricNames';
import { withObservePlanGateHandlingAsync } from '../../observe/planGating';
import { buildObserveEventsJson, buildObserveEventsTable } from '../../observe/formatEvents';
import { appObservePlatformFromFlag, appPlatformsFromFlag } from '../../observe/platforms';
import { observePlatformTargetsFromFlag, observePlatformsFromFlag } from '../../observe/platforms';
import { resolveObserveCommandContextAsync } from '../../observe/resolveProjectContext';
import { resolveTimeRange } from '../../observe/startAndEndTime';
import { selectAsync } from '../../prompts';
Expand Down Expand Up @@ -110,8 +110,8 @@ export default class ObserveMetrics extends EasCommand {

const { daysBack, startTime, endTime } = resolveTimeRange(flags);

const platform = appObservePlatformFromFlag(flags.platform);
const platforms = appPlatformsFromFlag(flags.platform);
const platforms = observePlatformsFromFlag(flags.platform);
const targets = observePlatformTargetsFromFlag(flags.platform);

const [{ events, pageInfo }, totalEventCount] = await withObservePlanGateHandlingAsync(() =>
Promise.all([
Expand All @@ -122,7 +122,7 @@ export default class ObserveMetrics extends EasCommand {
...(flags.after && { after: flags.after }),
startTime,
endTime,
platform,
platforms,
appVersion: flags['app-version'],
updateId: flags['update-id'],
environment: flags.environment,
Expand All @@ -131,7 +131,7 @@ export default class ObserveMetrics extends EasCommand {
graphqlClient,
projectId,
metricName,
platforms,
targets,
startTime,
endTime,
flags.environment
Expand Down
Loading
Loading