Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions packages/eas-cli/src/__tests__/commands/build-version-set-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,122 @@
await expect(cmd.run()).rejects.toThrowError('Aborted.');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});

describe('non-interactive mode with --value flag', () => {
test('setting version for android with --value flag', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);

const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android', '--value=130'], ctx);
await cmd.run();

expect(prompts.promptAsync).not.toHaveBeenCalled();
expect(AppVersionMutation.createAppVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
expect.objectContaining({
buildVersion: '130',
})
);
});

test('setting version for ios with --value flag', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);

const cmd = mockTestCommand(BuildVersionSetView, ['--platform=ios', '--value=1.2.3'], ctx);
await cmd.run();

expect(prompts.promptAsync).not.toHaveBeenCalled();
expect(AppVersionMutation.createAppVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
expect.objectContaining({
buildVersion: '1.2.3',
})
);
});

test('throws error when --value provided without --platform', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());

const cmd = mockTestCommand(BuildVersionSetView, ['--value=130'], ctx);

await expect(cmd.run()).rejects.toThrowError(
'--platform flag is required in non-interactive mode'
);
});

test('throws error for invalid android versionCode', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);

const cmd = mockTestCommand(
BuildVersionSetView,
['--platform=android', '--value=invalid'],
ctx
);

await expect(cmd.run()).rejects.toThrowError('Invalid versionCode');
});

test('throws error for invalid ios buildNumber', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);

const cmd = mockTestCommand(

Check warning on line 283 in packages/eas-cli/src/__tests__/commands/build-version-set-test.ts

View workflow job for this annotation

GitHub Actions / Test with Node 24

Replace `⏎········BuildVersionSetView,⏎········['--platform=ios',·'--value=1.2.3.4'],⏎········ctx⏎······` with `BuildVersionSetView,·['--platform=ios',·'--value=1.2.3.4'],·ctx`

Check warning on line 283 in packages/eas-cli/src/__tests__/commands/build-version-set-test.ts

View workflow job for this annotation

GitHub Actions / Test with Node 22

Replace `⏎········BuildVersionSetView,⏎········['--platform=ios',·'--value=1.2.3.4'],⏎········ctx⏎······` with `BuildVersionSetView,·['--platform=ios',·'--value=1.2.3.4'],·ctx`
BuildVersionSetView,
['--platform=ios', '--value=1.2.3.4'],
ctx
);

await expect(cmd.run()).rejects.toThrowError('Invalid buildNumber');
});

test('throws error for android versionCode exceeding max', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);

const cmd = mockTestCommand(
BuildVersionSetView,
['--platform=android', '--value=2100000001'],
ctx
);

await expect(cmd.run()).rejects.toThrowError('Invalid versionCode');
});

test('--non-interactive flag without --value throws error', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());

const cmd = mockTestCommand(
BuildVersionSetView,
['--platform=android', '--non-interactive'],
ctx
);

await expect(cmd.run()).rejects.toThrowError(
'--value flag is required in non-interactive mode'
);
});
});
});
57 changes: 45 additions & 12 deletions packages/eas-cli/src/commands/build/version/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import chalk from 'chalk';

import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../../../commandUtils/EasCommand';
import { EASNonInteractiveFlag } from '../../../commandUtils/flags';
import { AppVersionMutation } from '../../../graphql/mutations/AppVersionMutation';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
import { toAppPlatform } from '../../../graphql/types/AppPlatform';
Expand Down Expand Up @@ -36,6 +37,12 @@ export default class BuildVersionSetView extends EasCommand {
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.',
helpValue: 'PROFILE_NAME',
}),
value: Flags.string({
char: 'v',
description: 'Version value to set (versionCode for Android, buildNumber for iOS)',
helpValue: 'VERSION',
}),
...EASNonInteractiveFlag,
};

static override contextDefinition = {
Expand All @@ -47,19 +54,30 @@ export default class BuildVersionSetView extends EasCommand {

public async runAsync(): Promise<void> {
const { flags } = await this.parse(BuildVersionSetView);
const nonInteractive = flags['non-interactive'] ?? !!flags.value;

if (nonInteractive && !flags.platform) {
throw new Error(
'--platform flag is required in non-interactive mode. Use --platform=android or --platform=ios.'
);
}
if (nonInteractive && !flags.value) {
throw new Error('--value flag is required in non-interactive mode.');
}

const {
loggedIn: { graphqlClient },
getDynamicPrivateProjectConfigAsync,
projectDir,
vcsClient,
} = await this.getContextAsync(BuildVersionSetView, {
nonInteractive: false,
nonInteractive,
withServerSideEnvironment: null,
});

const platform = await selectPlatformAsync(flags.platform);
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
await ensureVersionSourceIsRemoteAsync(easJsonAccessor, { nonInteractive: false });
await ensureVersionSourceIsRemoteAsync(easJsonAccessor, { nonInteractive });
const profile = await EasJsonUtils.getBuildProfileAsync(
easJsonAccessor,
platform,
Expand All @@ -85,7 +103,7 @@ export default class BuildVersionSetView extends EasCommand {
buildProfile: profile,
platform,
vcsClient,
nonInteractive: false,
nonInteractive,
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
Expand All @@ -111,15 +129,30 @@ export default class BuildVersionSetView extends EasCommand {
: `What version would you like to initialize it with?`;
Log.log(currentStateMessage);

const { version } = await promptAsync({
type: platform === Platform.ANDROID ? 'number' : 'text',
name: 'version',
message: versionPromptMessage,
validate:
platform === Platform.ANDROID
? value => isValidVersionCode(value) || `Invalid value: ${VERSION_CODE_REQUIREMENTS}.`
: value => isValidBuildNumber(value) || `Invalid value: ${BUILD_NUMBER_REQUIREMENTS}.`,
});
let version: string | number;
if (flags.value) {
if (platform === Platform.ANDROID) {
if (!isValidVersionCode(flags.value)) {
throw new Error(`Invalid versionCode: ${VERSION_CODE_REQUIREMENTS}.`);
}
} else {
if (!isValidBuildNumber(flags.value)) {
throw new Error(`Invalid buildNumber: ${BUILD_NUMBER_REQUIREMENTS}.`);
}
}
version = flags.value;
} else {
const result = await promptAsync({
type: platform === Platform.ANDROID ? 'number' : 'text',
name: 'version',
message: versionPromptMessage,
validate:
platform === Platform.ANDROID
? value => isValidVersionCode(value) || `Invalid value: ${VERSION_CODE_REQUIREMENTS}.`
: value => isValidBuildNumber(value) || `Invalid value: ${BUILD_NUMBER_REQUIREMENTS}.`,
});
version = result.version;
}
await AppVersionMutation.createAppVersionAsync(graphqlClient, {
appId: projectId,
platform: toAppPlatform(platform),
Expand Down
Loading