Skip to content

Commit e21ac36

Browse files
committed
[eas-cli] Add eas update:upload-embedded command
1 parent 7a40d10 commit e21ac36

5 files changed

Lines changed: 24 additions & 48 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This is the log of notable changes to EAS CLI and related packages.
88

99
### 🎉 New features
1010

11-
- [eas-cli] Add `eas update:upload-embedded` command to upload the JS bundle embedded in a native build so EAS Update can generate bsdiff patches against it. ([#TODO](https://github.com/expo/eas-cli/pull/TODO) by [@gwdp](https://github.com/gwdp))
11+
- [eas-cli] Add `eas update:upload-embedded` command to upload the JS bundle embedded in a native build so EAS Update can generate bsdiff patches against it. ([#3699](https://github.com/expo/eas-cli/pull/3699) by [@gwdp](https://github.com/gwdp))
1212

1313
### 🐛 Bug fixes
1414

packages/eas-cli/src/commands/update/__tests__/upload-embedded.test.ts

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import { vol } from 'memfs';
44

55
import { getMockOclifConfig } from '../../../__tests__/commands/utils';
66
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
7-
import { ChannelNotFoundError } from '../../../channel/errors';
87
import { EmbeddedUpdateAssetMutation } from '../../../graphql/mutations/EmbeddedUpdateAssetMutation';
98
import {
109
EmbeddedUpdateMutation,
1110
isEmbeddedUpdateAssetNotReadyError,
1211
isEmbeddedUpdateConflictError,
1312
} from '../../../graphql/mutations/EmbeddedUpdateMutation';
1413
import { AppPlatform } from '../../../graphql/generated';
15-
import { ChannelQuery } from '../../../graphql/queries/ChannelQuery';
1614
import Log from '../../../log';
1715
import * as uploads from '../../../uploads';
1816
import * as promise from '../../../utils/promise';
@@ -30,9 +28,6 @@ jest.mock('../../../graphql/mutations/EmbeddedUpdateMutation', () => ({
3028
isEmbeddedUpdateAssetNotReadyError: jest.fn(),
3129
isEmbeddedUpdateConflictError: jest.fn(),
3230
}));
33-
jest.mock('../../../graphql/queries/ChannelQuery', () => ({
34-
ChannelQuery: { viewUpdateChannelBasicInfoAsync: jest.fn() },
35-
}));
3631
jest.mock('../../../uploads');
3732
jest.mock('../../../log');
3833
jest.mock('../../../utils/promise', () => ({
@@ -41,7 +36,6 @@ jest.mock('../../../utils/promise', () => ({
4136

4237
const mockGetRuntimeVersion = jest.mocked(Updates.getRuntimeVersionNullableAsync);
4338
const mockGetSignedUploadSpec = jest.mocked(EmbeddedUpdateAssetMutation.getSignedUploadSpecAsync);
44-
const mockViewChannel = jest.mocked(ChannelQuery.viewUpdateChannelBasicInfoAsync);
4539
const mockUpload = jest.mocked(uploads.uploadWithPresignedPostWithRetryAsync);
4640
const mockLogLog = jest.mocked(Log.log);
4741
const mockUploadEmbeddedUpdate = jest.mocked(EmbeddedUpdateMutation.uploadEmbeddedUpdateAsync);
@@ -78,7 +72,7 @@ const MOCK_EMBEDDED_UPDATE = {
7872
id: 'embedded-update-id-abc',
7973
platform: AppPlatform.Ios,
8074
runtimeVersion: '1.0.0',
81-
channelId: 'channel-id-123',
75+
channel: 'production',
8276
createdAt: '2024-01-01T00:00:00Z',
8377
};
8478

@@ -93,7 +87,6 @@ describe(UpdateUploadEmbedded, () => {
9387
[MANIFEST_PATH]: VALID_MANIFEST,
9488
});
9589
mockGetRuntimeVersion.mockResolvedValue('1.0.0');
96-
mockViewChannel.mockResolvedValue({ id: 'channel-id-123', name: 'production' } as any);
9790
mockGetSignedUploadSpec.mockResolvedValue({
9891
storageKey: 'storage-key-abc',
9992
presignedUrl: 'https://storage.googleapis.com/upload-bucket',
@@ -184,31 +177,15 @@ describe(UpdateUploadEmbedded, () => {
184177
});
185178
});
186179

187-
describe('channel resolution', () => {
188-
it('resolves channel by name and app id', async () => {
189-
const command = createCommand(BASE_ARGV);
190-
await command.runAsync();
191-
expect(mockViewChannel).toHaveBeenCalledWith(
192-
MOCK_CONTEXT.loggedIn.graphqlClient,
193-
{ appId: MOCK_CONTEXT.privateProjectConfig.projectId, channelName: 'production' }
194-
);
195-
});
196-
197-
it('propagates ChannelNotFoundError when channel does not exist', async () => {
198-
mockViewChannel.mockRejectedValue(new ChannelNotFoundError('Channel not found'));
199-
const command = createCommand(BASE_ARGV);
200-
await expect(command.runAsync()).rejects.toThrow(ChannelNotFoundError);
201-
});
202-
});
203-
204180
describe('bundle upload', () => {
205-
it('requests a presigned URL and uploads the bundle', async () => {
181+
it('requests a presigned URL with embeddedUpdateId and uploads the bundle', async () => {
206182
const command = createCommand(BASE_ARGV);
207183
await command.runAsync();
208184
expect(mockGetSignedUploadSpec).toHaveBeenCalledWith(
209185
MOCK_CONTEXT.loggedIn.graphqlClient,
210186
expect.objectContaining({
211187
appId: MOCK_CONTEXT.privateProjectConfig.projectId,
188+
embeddedUpdateId: VALID_UUID,
212189
contentType: 'application/javascript',
213190
})
214191
);
@@ -227,7 +204,7 @@ describe(UpdateUploadEmbedded, () => {
227204
});
228205

229206
describe('mutation registration', () => {
230-
it('calls uploadEmbeddedUpdateAsync with all collected inputs including AppPlatform enum', async () => {
207+
it('calls uploadEmbeddedUpdateAsync with channel name and AppPlatform enum', async () => {
231208
const command = createCommand(BASE_ARGV);
232209
await command.runAsync();
233210
expect(mockUploadEmbeddedUpdate).toHaveBeenCalledWith(
@@ -236,9 +213,8 @@ describe(UpdateUploadEmbedded, () => {
236213
appId: MOCK_CONTEXT.privateProjectConfig.projectId,
237214
platform: AppPlatform.Ios,
238215
runtimeVersion: '1.0.0',
239-
channelId: 'channel-id-123',
216+
channel: 'production',
240217
embeddedUpdateId: VALID_UUID,
241-
launchAssetStorageKey: 'storage-key-abc',
242218
})
243219
);
244220
});

packages/eas-cli/src/commands/update/upload-embedded.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
isEmbeddedUpdateAssetNotReadyError,
1616
isEmbeddedUpdateConflictError,
1717
} from '../../graphql/mutations/EmbeddedUpdateMutation';
18-
import { ChannelQuery } from '../../graphql/queries/ChannelQuery';
1918
import { toAppPlatform } from '../../graphql/types/AppPlatform';
2019
import Log from '../../log';
2120
import { readEmbeddedManifest } from '../../update/embeddedManifest';
@@ -115,11 +114,6 @@ export default class UpdateUploadEmbedded extends EasCommand {
115114
}
116115

117116
const appPlatform = toAppPlatform(platform);
118-
const channel = await ChannelQuery.viewUpdateChannelBasicInfoAsync(graphqlClient, {
119-
appId: projectId,
120-
channelName,
121-
});
122-
const channelId = channel.id;
123117

124118
Log.log(
125119
`Uploading embedded ${platform} bundle to channel "${channelName}"` +
@@ -129,6 +123,7 @@ export default class UpdateUploadEmbedded extends EasCommand {
129123
const contentType = 'application/javascript';
130124
const uploadSpec = await EmbeddedUpdateAssetMutation.getSignedUploadSpecAsync(graphqlClient, {
131125
appId: projectId,
126+
embeddedUpdateId,
132127
contentType,
133128
});
134129
const presignedPost: PresignedPost = {
@@ -140,7 +135,7 @@ export default class UpdateUploadEmbedded extends EasCommand {
140135
});
141136

142137
Log.debug(
143-
`Bundle uploaded. storageKey: ${uploadSpec.storageKey}, embeddedUpdateId: ${embeddedUpdateId}, runtimeVersion: ${runtimeVersion}, channelId: ${channelId}`
138+
`Bundle uploaded. storageKey: ${uploadSpec.storageKey}, embeddedUpdateId: ${embeddedUpdateId}, runtimeVersion: ${runtimeVersion}, channel: ${channelName}`
144139
);
145140

146141
let embeddedUpdate: EmbeddedUpdateResult | undefined;
@@ -150,9 +145,8 @@ export default class UpdateUploadEmbedded extends EasCommand {
150145
appId: projectId,
151146
platform: appPlatform,
152147
runtimeVersion,
153-
channelId,
148+
channel: channelName,
154149
embeddedUpdateId,
155-
launchAssetStorageKey: uploadSpec.storageKey,
156150
turtleBuildId: buildId,
157151
});
158152
break;
@@ -166,9 +160,10 @@ export default class UpdateUploadEmbedded extends EasCommand {
166160
{ exit: 1 }
167161
);
168162
}
169-
const delayMs = attempt < MAX_ATTEMPTS
170-
? Math.min(RETRY_BASE_DELAY_MS * 2 ** (attempt - 1), RETRY_MAX_DELAY_MS)
171-
: undefined;
163+
const delayMs =
164+
attempt < MAX_ATTEMPTS
165+
? Math.min(RETRY_BASE_DELAY_MS * 2 ** (attempt - 1), RETRY_MAX_DELAY_MS)
166+
: undefined;
172167
if (isEmbeddedUpdateAssetNotReadyError(e) && delayMs !== undefined) {
173168
Log.log(
174169
`Asset not yet finalized, retrying (attempt ${attempt + 1}/${MAX_ATTEMPTS})...`

packages/eas-cli/src/graphql/mutations/EmbeddedUpdateAssetMutation.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,25 @@ type GetSignedEmbeddedUploadSpecMutationResult = {
1818
export const EmbeddedUpdateAssetMutation = {
1919
async getSignedUploadSpecAsync(
2020
graphqlClient: ExpoGraphqlClient,
21-
{ appId, contentType }: { appId: string; contentType: string }
21+
{
22+
appId,
23+
embeddedUpdateId,
24+
contentType,
25+
}: { appId: string; embeddedUpdateId: string; contentType: string }
2226
): Promise<EmbeddedUpdateAssetUploadSpec> {
2327
const data = await withErrorHandlingAsync(
2428
graphqlClient
2529
.mutation<GetSignedEmbeddedUploadSpecMutationResult>(
2630
gql`
2731
mutation GetSignedEmbeddedUpdateAssetUploadSpec(
2832
$appId: ID!
33+
$embeddedUpdateId: ID!
2934
$contentType: String!
3035
) {
3136
embeddedUpdateAsset {
3237
getSignedEmbeddedUpdateAssetUploadSpecifications(
3338
appId: $appId
39+
embeddedUpdateId: $embeddedUpdateId
3440
contentType: $contentType
3541
) {
3642
storageKey
@@ -40,7 +46,7 @@ export const EmbeddedUpdateAssetMutation = {
4046
}
4147
}
4248
`,
43-
{ appId, contentType }
49+
{ appId, embeddedUpdateId, contentType }
4450
)
4551
.toPromise()
4652
);

packages/eas-cli/src/graphql/mutations/EmbeddedUpdateMutation.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,16 @@ export type EmbeddedUpdateResult = {
99
id: string;
1010
platform: AppPlatform;
1111
runtimeVersion: string;
12-
channelId: string;
12+
channel: string;
1313
createdAt: string;
1414
};
1515

1616
type UploadEmbeddedUpdateInput = {
1717
appId: string;
1818
platform: AppPlatform;
1919
runtimeVersion: string;
20-
channelId: string;
20+
channel: string;
2121
embeddedUpdateId: string;
22-
launchAssetStorageKey: string;
2322
turtleBuildId?: string;
2423
};
2524

@@ -60,7 +59,7 @@ export const EmbeddedUpdateMutation = {
6059
id
6160
platform
6261
runtimeVersion
63-
channelId
62+
channel
6463
createdAt
6564
}
6665
}

0 commit comments

Comments
 (0)