Skip to content

Commit 01b997d

Browse files
committed
[eas-cli] Add eas update:view-embedded command
1 parent bf6d5eb commit 01b997d

2 files changed

Lines changed: 219 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Args, Errors } from '@oclif/core';
2+
3+
import EasCommand from '../../commandUtils/EasCommand';
4+
import { EasJsonOnlyFlag } from '../../commandUtils/flags';
5+
import {
6+
EmbeddedUpdateFragment,
7+
EmbeddedUpdateQuery,
8+
isEmbeddedUpdateNotFoundError,
9+
} from '../../graphql/queries/EmbeddedUpdateQuery';
10+
import Log from '../../log';
11+
import formatFields from '../../utils/formatFields';
12+
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
13+
14+
export default class UpdateViewEmbedded extends EasCommand {
15+
static override description = 'view details of an embedded update registered with EAS Update';
16+
17+
static override args = {
18+
id: Args.string({
19+
required: true,
20+
description: 'The ID of the embedded update (manifest UUID from app.manifest).',
21+
}),
22+
};
23+
24+
static override flags = {
25+
...EasJsonOnlyFlag,
26+
};
27+
28+
static override contextDefinition = {
29+
...this.ContextOptions.ProjectId,
30+
...this.ContextOptions.LoggedIn,
31+
};
32+
33+
async runAsync(): Promise<void> {
34+
const {
35+
args: { id: embeddedUpdateId },
36+
flags: { json: jsonFlag },
37+
} = await this.parse(UpdateViewEmbedded);
38+
39+
const {
40+
projectId,
41+
loggedIn: { graphqlClient },
42+
} = await this.getContextAsync(UpdateViewEmbedded, { nonInteractive: true });
43+
44+
if (jsonFlag) {
45+
enableJsonOutput();
46+
}
47+
48+
let embeddedUpdate;
49+
try {
50+
embeddedUpdate = await EmbeddedUpdateQuery.viewByIdAsync(graphqlClient, {
51+
embeddedUpdateId,
52+
appId: projectId,
53+
});
54+
} catch (e: unknown) {
55+
if (isEmbeddedUpdateNotFoundError(e)) {
56+
Errors.error(
57+
`No embedded update found with id "${embeddedUpdateId}" for this project. ` +
58+
`Verify the id is correct and belongs to this app.`,
59+
{ exit: 1 }
60+
);
61+
}
62+
throw e;
63+
}
64+
65+
if (jsonFlag) {
66+
printJsonOnlyOutput(embeddedUpdate);
67+
return;
68+
}
69+
70+
Log.log(formatEmbeddedUpdate(embeddedUpdate));
71+
}
72+
}
73+
74+
export function formatEmbeddedUpdate(embeddedUpdate: EmbeddedUpdateFragment): string {
75+
return formatFields([
76+
{ label: 'ID', value: embeddedUpdate.id },
77+
{ label: 'Platform', value: embeddedUpdate.platform.toLowerCase() },
78+
{ label: 'Runtime version', value: embeddedUpdate.runtimeVersion },
79+
{ label: 'Channel', value: embeddedUpdate.channel },
80+
{ label: 'Created at', value: new Date(embeddedUpdate.createdAt).toLocaleString() },
81+
]);
82+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { CombinedError } from '@urql/core';
2+
import gql from 'graphql-tag';
3+
4+
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
5+
import { AppPlatform } from '../generated';
6+
import { Connection } from '../../utils/relay';
7+
import { withErrorHandlingAsync } from '../client';
8+
9+
export function isEmbeddedUpdateNotFoundError(error: unknown): boolean {
10+
return (
11+
error instanceof CombinedError &&
12+
error.graphQLErrors.some(e => e.extensions?.['errorCode'] === 'EMBEDDED_UPDATE_NOT_FOUND')
13+
);
14+
}
15+
16+
export type EmbeddedUpdateFragment = {
17+
id: string;
18+
platform: AppPlatform;
19+
runtimeVersion: string;
20+
channel: string;
21+
createdAt: string;
22+
};
23+
24+
type ViewEmbeddedUpdateByIdQueryResult = {
25+
embeddedUpdates: {
26+
byId: EmbeddedUpdateFragment;
27+
};
28+
};
29+
30+
type ViewEmbeddedUpdatesPaginatedQueryResult = {
31+
app: {
32+
byId: {
33+
embeddedUpdatesPaginated: {
34+
edges: { cursor: string; node: EmbeddedUpdateFragment }[];
35+
pageInfo: {
36+
hasNextPage: boolean;
37+
hasPreviousPage: boolean;
38+
startCursor: string | null;
39+
endCursor: string | null;
40+
};
41+
};
42+
};
43+
};
44+
};
45+
46+
export type EmbeddedUpdateFilter = {
47+
platform?: AppPlatform;
48+
runtimeVersion?: string;
49+
channel?: string;
50+
};
51+
52+
export const EmbeddedUpdateQuery = {
53+
async viewByIdAsync(
54+
graphqlClient: ExpoGraphqlClient,
55+
{ embeddedUpdateId, appId }: { embeddedUpdateId: string; appId: string }
56+
): Promise<EmbeddedUpdateFragment> {
57+
const data = await withErrorHandlingAsync(
58+
graphqlClient
59+
.query<ViewEmbeddedUpdateByIdQueryResult>(
60+
gql`
61+
query ViewEmbeddedUpdateById($embeddedUpdateId: ID!, $appId: ID!) {
62+
embeddedUpdates {
63+
byId(embeddedUpdateId: $embeddedUpdateId, appId: $appId) {
64+
id
65+
platform
66+
runtimeVersion
67+
channel
68+
createdAt
69+
}
70+
}
71+
}
72+
`,
73+
{ embeddedUpdateId, appId },
74+
{ additionalTypenames: ['EmbeddedUpdate'] }
75+
)
76+
.toPromise()
77+
);
78+
return data.embeddedUpdates.byId;
79+
},
80+
81+
async viewPaginatedAsync(
82+
graphqlClient: ExpoGraphqlClient,
83+
{
84+
appId,
85+
filter,
86+
first,
87+
after,
88+
}: {
89+
appId: string;
90+
filter?: EmbeddedUpdateFilter;
91+
first: number;
92+
after?: string;
93+
}
94+
): Promise<Connection<EmbeddedUpdateFragment>> {
95+
const data = await withErrorHandlingAsync(
96+
graphqlClient
97+
.query<ViewEmbeddedUpdatesPaginatedQueryResult>(
98+
gql`
99+
query ViewEmbeddedUpdatesPaginated(
100+
$appId: String!
101+
$first: Int!
102+
$after: String
103+
$filter: EmbeddedUpdateFilterInput
104+
) {
105+
app {
106+
byId(appId: $appId) {
107+
id
108+
embeddedUpdatesPaginated(first: $first, after: $after, filter: $filter) {
109+
edges {
110+
cursor
111+
node {
112+
id
113+
platform
114+
runtimeVersion
115+
channel
116+
createdAt
117+
}
118+
}
119+
pageInfo {
120+
hasNextPage
121+
hasPreviousPage
122+
startCursor
123+
endCursor
124+
}
125+
}
126+
}
127+
}
128+
}
129+
`,
130+
{ appId, first, after, filter },
131+
{ additionalTypenames: ['EmbeddedUpdate'] }
132+
)
133+
.toPromise()
134+
);
135+
return data.app.byId.embeddedUpdatesPaginated;
136+
},
137+
};

0 commit comments

Comments
 (0)