Compare commits

...
6 changed files with 104 additions and 6 deletions

No files matched your search

+1
View File
@@ -9,6 +9,7 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Better description for update:rollback. ([#3154](https://github.com/expo/eas-cli/pull/3154) by [@douglowder](https://github.com/douglowder))
- Support native server deployments in EAS Update ([#3155](https://github.com/expo/eas-cli/pull/3155) by [@krystofwoldrich](https://github.com/krystofwoldrich))
### 🐛 Bug fixes
@@ -21,8 +21,9 @@ import { jester } from '../../../credentials/__tests__/fixtures-constants';
import { UpdateFragment } from '../../../graphql/generated';
import { PublishMutation } from '../../../graphql/mutations/PublishMutation';
import { AppQuery } from '../../../graphql/queries/AppQuery';
import { collectAssetsAsync, uploadAssetsAsync } from '../../../project/publish';
import { buildBundlesAsync, collectAssetsAsync, uploadAssetsAsync } from '../../../project/publish';
import { getBranchFromChannelNameAndCreateAndLinkIfNotExistsAsync } from '../../../update/getBranchFromChannelNameAndCreateAndLinkIfNotExistsAsync';
import { getTemporaryPath, safelyDeletePathAsync } from '../../../utils/temporaryPath';
import { resolveVcsClient } from '../../../vcs';
const projectRoot = '/test-project';
@@ -65,6 +66,7 @@ jest.mock('../../../project/publish', () => ({
resolveInputDirectoryAsync: jest.fn((inputDir = 'dist') => path.join(projectRoot, inputDir)),
uploadAssetsAsync: jest.fn(),
}));
jest.mock('../../../utils/temporaryPath.ts');
describe(UpdatePublish.name, () => {
afterEach(() => {
@@ -177,6 +179,60 @@ describe(UpdatePublish.name, () => {
// Ensure non-public config is not present
expect(expoConfig).not.toHaveProperty('hooks');
});
it('creates a new update with a native deployment', async () => {
const flags = ['--non-interactive', '--branch=branch123', '--message=abc'];
const { appJson } = mockTestProject();
const { platforms, runtimeVersion } = mockTestExport();
jest.mocked(buildBundlesAsync).mockImplementation(() => {
// Mock config changing during the build
// e.g. server url deployment
appJson.expo.extra = {
...appJson.expo.extra,
afterBuild: 'mocked',
};
return Promise.resolve();
});
// Mock the temporary path for the generated config
const mockedGeneratedConfigTmpPath = `/tmp/test-${Math.random().toString(36).substring(2)}`;
jest.mocked(getTemporaryPath).mockReturnValueOnce(mockedGeneratedConfigTmpPath);
// Mock an existing branch, so we don't create a new one
jest.mocked(ensureBranchExistsAsync).mockResolvedValue({
branch: {
id: 'branch123',
name: 'wat',
},
createdBranch: false,
});
jest
.mocked(PublishMutation.publishUpdateGroupAsync)
.mockResolvedValue(platforms.map(platform => ({ ...updateStub, platform, runtimeVersion })));
await new UpdatePublish(flags, commandOptions).run();
// Pull the publish data from the mocked publish function
const publishData = jest.mocked(PublishMutation.publishUpdateGroupAsync).mock.calls[0][1][0];
// Pull the Expo config from the publish data
const expoConfig = nullthrows(publishData.updateInfoGroup).ios!.extra.expoClient;
expect(getTemporaryPath).toHaveBeenCalledTimes(1);
expect(safelyDeletePathAsync).toHaveBeenCalledTimes(1);
expect(safelyDeletePathAsync).toHaveBeenCalledWith(mockedGeneratedConfigTmpPath);
expect(buildBundlesAsync).toHaveBeenCalledWith(
expect.objectContaining({
extraEnv: expect.objectContaining({
__EXPO_GENERATED_CONFIG_PATH: mockedGeneratedConfigTmpPath,
}),
})
);
expect(expoConfig?.extra?.afterBuild).toEqual('mocked');
});
});
/** Create a new in-memory project, copied from src/commands/update/__tests__/republish.test.ts */
+21 -2
View File
@@ -65,6 +65,7 @@ import uniqBy from '../../utils/expodash/uniqBy';
import formatFields from '../../utils/formatFields';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
import { maybeWarnAboutEasOutagesAsync } from '../../utils/statuspageService';
import { getTemporaryPath, safelyDeletePathAsync } from '../../utils/temporaryPath';
type RawUpdateFlags = {
auto: boolean;
@@ -167,6 +168,15 @@ export default class UpdatePublish extends EasCommand {
};
async runAsync(): Promise<void> {
const generatedConfigPath = getTemporaryPath();
try {
await this.runUnsafeAsync(generatedConfigPath);
} finally {
await safelyDeletePathAsync(generatedConfigPath);
}
}
private async runUnsafeAsync(generatedConfigPath: string): Promise<void> {
const { flags: rawFlags } = await this.parse(UpdatePublish);
const paginatedQueryOptions = getPaginatedQueryOptions(rawFlags);
const {
@@ -262,7 +272,10 @@ export default class UpdatePublish extends EasCommand {
exp,
platformFlag: requestedPlatform,
clearCache,
extraEnv: maybeServerEnv,
extraEnv: {
...maybeServerEnv,
__EXPO_GENERATED_CONFIG_PATH: generatedConfigPath,
},
});
bundleSpinner.succeed('Exported bundle(s)');
} catch (e) {
@@ -351,7 +364,13 @@ export default class UpdatePublish extends EasCommand {
uploadedAssetCount = uploadResults.uniqueUploadedAssetCount;
assetLimitPerUpdateGroup = uploadResults.assetLimitPerUpdateGroup;
unsortedUpdateInfoGroups = await buildUnsortedUpdateInfoGroupAsync(assets, exp);
const { exp: expAfterBuild } = await getDynamicPublicProjectConfigAsync({
env: {
__EXPO_GENERATED_CONFIG_PATH: generatedConfigPath,
},
});
unsortedUpdateInfoGroups = await buildUnsortedUpdateInfoGroupAsync(assets, expAfterBuild);
// NOTE(cedric): we assume that bundles are always uploaded, and always are part of
// `uploadedAssetCount`, perferably we don't assume. For that, we need to refactor the
+9 -3
View File
@@ -42,6 +42,7 @@ import {
truncateString as truncateUpdateMessage,
} from '../update/utils';
import { PresignedPost, uploadWithPresignedPostWithRetryAsync } from '../uploads';
import { easCliBin } from '../utils/easCli';
import {
expoCommandAsync,
shouldUseVersionedExpoCLI,
@@ -223,6 +224,11 @@ export async function buildBundlesAsync({
throw new Error('Could not locate package.json');
}
const extendedEnv = {
...extraEnv,
__EAS_BIN: easCliBin,
};
// Legacy global Expo CLI
if (!shouldUseVersionedExpoCLI(projectDir, exp)) {
await expoCommandAsync(
@@ -239,7 +245,7 @@ export async function buildBundlesAsync({
...(clearCache ? ['--clear'] : []),
],
{
extraEnv,
extraEnv: extendedEnv,
}
);
return;
@@ -265,7 +271,7 @@ export async function buildBundlesAsync({
...(clearCache ? ['--clear'] : []),
],
{
extraEnv,
extraEnv: extendedEnv,
}
);
return;
@@ -293,7 +299,7 @@ export async function buildBundlesAsync({
...(clearCache ? ['--clear'] : []),
],
{
extraEnv,
extraEnv: extendedEnv,
}
);
}
+3
View File
@@ -1,3 +1,6 @@
import { argv } from 'node:process';
const packageJSON = require('../../package.json');
export const easCliVersion: string = packageJSON.version;
export const easCliBin: string = argv[1];
@@ -0,0 +1,13 @@
import * as fs from 'node:fs/promises';
import * as os from 'node:os';
import * as path from 'node:path';
export function getTemporaryPath(): string {
return path.join(os.tmpdir(), Math.random().toString(36).substring(2));
}
export async function safelyDeletePathAsync(value: string): Promise<void> {
try {
await fs.rm(value, { recursive: true, force: true });
} catch {}
}