Skip to content

Commit 742513e

Browse files
committed
[eas-cli] Add eas update:embedded:view command
1 parent b00b30e commit 742513e

3 files changed

Lines changed: 231 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This is the log of notable changes to EAS CLI and related packages.
99
### 🎉 New features
1010

1111
- [eas-cli] Add `eas update:embedded:upload` command. ([#3720](https://github.com/expo/eas-cli/pull/3720) by [@gwdp](https://github.com/gwdp))
12+
- [eas-cli] Add `eas update:embedded:view` command. ([#3721](https://github.com/expo/eas-cli/pull/3721) by [@gwdp](https://github.com/gwdp))
1213

1314
### 🐛 Bug fixes
1415

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 UpdateEmbeddedView 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(UpdateEmbeddedView);
38+
39+
const {
40+
projectId,
41+
loggedIn: { graphqlClient },
42+
} = await this.getContextAsync(UpdateEmbeddedView, { 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: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import { CombinedError } from '@urql/core';
2+
import gql from 'graphql-tag';
3+
4+
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
5+
import { AppPlatform, EmbeddedUpdate } 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+
// Query result types are defined manually because the embeddedUpdates query fields
17+
// are not yet included in the GraphQL codegen schema.
18+
export type EmbeddedUpdateFragment = Pick<
19+
EmbeddedUpdate,
20+
'id' | 'platform' | 'runtimeVersion' | 'channel' | 'createdAt'
21+
>;
22+
23+
type ViewEmbeddedUpdateByIdQueryResult = {
24+
embeddedUpdates: {
25+
byId: EmbeddedUpdateFragment;
26+
};
27+
};
28+
29+
type ViewEmbeddedUpdateByIdQueryVariables = {
30+
embeddedUpdateId: string;
31+
appId: string;
32+
};
33+
34+
type ViewEmbeddedUpdatesPaginatedQueryResult = {
35+
app: {
36+
byId: {
37+
embeddedUpdatesPaginated: {
38+
edges: { cursor: string; node: EmbeddedUpdateFragment }[];
39+
pageInfo: {
40+
hasNextPage: boolean;
41+
hasPreviousPage: boolean;
42+
startCursor: string | null;
43+
endCursor: string | null;
44+
};
45+
};
46+
};
47+
};
48+
};
49+
50+
type ViewEmbeddedUpdatesPaginatedQueryVariables = {
51+
appId: string;
52+
first: number;
53+
after?: string;
54+
filter?: EmbeddedUpdateFilter;
55+
};
56+
57+
export type EmbeddedUpdateFilter = {
58+
platform?: AppPlatform;
59+
runtimeVersion?: string;
60+
channel?: string;
61+
};
62+
63+
export const EmbeddedUpdateQuery = {
64+
async viewByIdAsync(
65+
graphqlClient: ExpoGraphqlClient,
66+
{ embeddedUpdateId, appId }: { embeddedUpdateId: string; appId: string }
67+
): Promise<EmbeddedUpdateFragment> {
68+
const data = await withErrorHandlingAsync(
69+
graphqlClient
70+
.query<ViewEmbeddedUpdateByIdQueryResult, ViewEmbeddedUpdateByIdQueryVariables>(
71+
gql`
72+
query ViewEmbeddedUpdateById($embeddedUpdateId: ID!, $appId: ID!) {
73+
embeddedUpdates {
74+
byId(embeddedUpdateId: $embeddedUpdateId, appId: $appId) {
75+
id
76+
platform
77+
runtimeVersion
78+
channel
79+
createdAt
80+
}
81+
}
82+
}
83+
`,
84+
{ embeddedUpdateId, appId },
85+
{ additionalTypenames: ['EmbeddedUpdate'] }
86+
)
87+
.toPromise()
88+
);
89+
return data.embeddedUpdates.byId;
90+
},
91+
92+
async viewPaginatedAsync(
93+
graphqlClient: ExpoGraphqlClient,
94+
{
95+
appId,
96+
filter,
97+
first,
98+
after,
99+
}: {
100+
appId: string;
101+
filter?: EmbeddedUpdateFilter;
102+
first: number;
103+
after?: string;
104+
}
105+
): Promise<Connection<EmbeddedUpdateFragment>> {
106+
const data = await withErrorHandlingAsync(
107+
graphqlClient
108+
.query<ViewEmbeddedUpdatesPaginatedQueryResult, ViewEmbeddedUpdatesPaginatedQueryVariables>(
109+
gql`
110+
query ViewEmbeddedUpdatesPaginated(
111+
$appId: String!
112+
$first: Int!
113+
$after: String
114+
$filter: EmbeddedUpdateFilterInput
115+
) {
116+
app {
117+
byId(appId: $appId) {
118+
id
119+
embeddedUpdatesPaginated(first: $first, after: $after, filter: $filter) {
120+
edges {
121+
cursor
122+
node {
123+
id
124+
platform
125+
runtimeVersion
126+
channel
127+
createdAt
128+
}
129+
}
130+
pageInfo {
131+
hasNextPage
132+
hasPreviousPage
133+
startCursor
134+
endCursor
135+
}
136+
}
137+
}
138+
}
139+
}
140+
`,
141+
{ appId, first, after, filter },
142+
{ additionalTypenames: ['EmbeddedUpdate'] }
143+
)
144+
.toPromise()
145+
);
146+
return data.app.byId.embeddedUpdatesPaginated;
147+
},
148+
};

0 commit comments

Comments
 (0)