mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-15 03:38:08 -10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
434e00e7c2 | ||
|
|
88a88a0557 | ||
|
|
d18fdd8c38 | ||
|
|
d2393a7b08 | ||
|
|
fa5e71d0f2 | ||
|
|
838c1edec9 | ||
|
|
cd85de9d1b |
No files matched your search
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
Reference in new issue
Block a user