Skip to content
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This is the log of notable changes to EAS CLI and related packages.

### 🎉 New features

- [eas-cli] Add `--skip-screenshots` and `--skip-previews` flags to `eas metadata:pull` and `eas metadata:push` to skip downloading or uploading screenshots and video previews. ([#3843](https://github.com/expo/eas-cli/pull/3843) by [@TimBroddin](https://github.com/TimBroddin))

### 🐛 Bug fixes

- [expo-cocoapods-proxy] Fix iOS worker tarball build failing on macOS Tahoe due to bundler incompatibility with RubyGems 4. ([#3824](https://github.com/expo/eas-cli/pull/3824) by [@gwdp](https://github.com/gwdp))
Expand Down
17 changes: 11 additions & 6 deletions packages/eas-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1875,11 +1875,13 @@ generate the local store configuration from the app stores

```
USAGE
$ eas metadata:pull [-e <value>] [--non-interactive]
$ eas metadata:pull [-e <value>] [--skip-screenshots] [--skip-previews] [--non-interactive]

FLAGS
-e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.
--non-interactive Run the command in non-interactive mode.
-e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.
--non-interactive Run the command in non-interactive mode.
--skip-previews Skip downloading video previews from the app stores
--skip-screenshots Skip downloading screenshots from the app stores

DESCRIPTION
generate the local store configuration from the app stores
Expand All @@ -1893,11 +1895,14 @@ sync the local store configuration to the app stores

```
USAGE
$ eas metadata:push [-e <value>] [--non-interactive]
$ eas metadata:push [-e <value>] [--skip-screenshots] [--skip-previews] [--non-interactive]

FLAGS
-e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.
--non-interactive Run the command in non-interactive mode.
-e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.
--non-interactive Run the command in non-interactive mode.
--skip-previews Skip uploading video previews to the app stores. Video previews missing from the store config
are not deleted from the app stores.
--skip-screenshots Skip uploading screenshots to the app stores

DESCRIPTION
sync the local store configuration to the app stores
Expand Down
18 changes: 18 additions & 0 deletions packages/eas-cli/src/commands/metadata/pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export default class MetadataPull extends EasCommand {
description:
'Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.',
}),
'skip-screenshots': Flags.boolean({
description: 'Skip downloading screenshots from the app stores',
default: false,
}),
'skip-previews': Flags.boolean({
description: 'Skip downloading video previews from the app stores',
default: false,
}),
...EASNonInteractiveFlag,
};

Expand All @@ -47,6 +55,14 @@ export default class MetadataPull extends EasCommand {
withServerSideEnvironment: null,
});

if (flags['skip-previews']) {
Log.warn(
`Skipping video previews. Pushing the generated store config without ${chalk.bold(
'--skip-previews'
)} will delete existing video previews from the app stores.`
);
}

await ensureProjectConfiguredAsync({ projectDir, nonInteractive, vcsClient });

const submitProfiles = await getProfilesAsync({
Expand Down Expand Up @@ -82,6 +98,8 @@ export default class MetadataPull extends EasCommand {
nonInteractive,
graphqlClient,
projectId,
skipScreenshots: flags['skip-screenshots'],
skipPreviews: flags['skip-previews'],
});
const relativePath = path.relative(process.cwd(), filePath);

Expand Down
11 changes: 11 additions & 0 deletions packages/eas-cli/src/commands/metadata/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ export default class MetadataPush extends EasCommand {
description:
'Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.',
}),
'skip-screenshots': Flags.boolean({
description: 'Skip uploading screenshots to the app stores',
default: false,
}),
'skip-previews': Flags.boolean({
description:
'Skip uploading video previews to the app stores. Video previews missing from the store config are not deleted from the app stores.',
default: false,
}),
...EASNonInteractiveFlag,
};

Expand Down Expand Up @@ -80,6 +89,8 @@ export default class MetadataPush extends EasCommand {
nonInteractive,
graphqlClient,
projectId,
skipScreenshots: flags['skip-screenshots'],
skipPreviews: flags['skip-previews'],
});

Log.addNewLineIfNone();
Expand Down
25 changes: 25 additions & 0 deletions packages/eas-cli/src/metadata/__tests__/download.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ jest.mock('../../prompts', () => ({
}));

const { confirmAsync } = require('../../prompts') as jest.Mocked<typeof import('../../prompts')>;
const { createAppleTasks } = require('../apple/tasks') as jest.Mocked<
typeof import('../apple/tasks')
>;

function createArgs(overrides: Record<string, any> = {}) {
return {
Expand Down Expand Up @@ -97,4 +100,26 @@ describe(downloadMetadataAsync, () => {

expect(confirmAsync).not.toHaveBeenCalled();
});

it('does not skip screenshots or previews by default', async () => {
await downloadMetadataAsync(createArgs());

expect(createAppleTasks).toHaveBeenCalledWith(
expect.objectContaining({ skipScreenshots: false, skipPreviews: false })
);
});

it('skips screenshots when skipScreenshots is enabled', async () => {
await downloadMetadataAsync(createArgs({ skipScreenshots: true }));

expect(createAppleTasks).toHaveBeenCalledWith(
expect.objectContaining({ skipScreenshots: true })
);
});

it('skips previews when skipPreviews is enabled', async () => {
await downloadMetadataAsync(createArgs({ skipPreviews: true }));

expect(createAppleTasks).toHaveBeenCalledWith(expect.objectContaining({ skipPreviews: true }));
});
});
25 changes: 25 additions & 0 deletions packages/eas-cli/src/metadata/__tests__/upload.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const { loadConfigAsync } = require('../config/resolve') as jest.Mocked<
typeof import('../config/resolve')
>;
const { confirmAsync } = require('../../prompts') as jest.Mocked<typeof import('../../prompts')>;
const { createAppleTasks } = require('../apple/tasks') as jest.Mocked<
typeof import('../apple/tasks')
>;

function createArgs(overrides: Record<string, any> = {}) {
return {
Expand Down Expand Up @@ -100,4 +103,26 @@ describe(uploadMetadataAsync, () => {
expect(result).toHaveProperty('appleLink');
expect(result.appleLink).toContain('appstoreconnect.apple.com');
});

it('does not skip screenshots or previews by default', async () => {
await uploadMetadataAsync(createArgs());

expect(createAppleTasks).toHaveBeenCalledWith(
expect.objectContaining({ skipScreenshots: false, skipPreviews: false })
);
});

it('skips screenshots when skipScreenshots is enabled', async () => {
await uploadMetadataAsync(createArgs({ skipScreenshots: true }));

expect(createAppleTasks).toHaveBeenCalledWith(
expect.objectContaining({ skipScreenshots: true })
);
});

it('skips previews when skipPreviews is enabled', async () => {
await uploadMetadataAsync(createArgs({ skipPreviews: true }));

expect(createAppleTasks).toHaveBeenCalledWith(expect.objectContaining({ skipPreviews: true }));
});
});
39 changes: 39 additions & 0 deletions packages/eas-cli/src/metadata/apple/tasks/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createAppleTasks } from '../index';
import { PreviewsTask } from '../previews';
import { ScreenshotsTask } from '../screenshots';

describe(createAppleTasks, () => {
it('includes the screenshots and previews tasks by default', () => {
const tasks = createAppleTasks();

expect(tasks.some(task => task instanceof ScreenshotsTask)).toBe(true);
expect(tasks.some(task => task instanceof PreviewsTask)).toBe(true);
});

it('omits the screenshots task when skipScreenshots is enabled', () => {
const defaultTasks = createAppleTasks();
const tasks = createAppleTasks({ skipScreenshots: true });

expect(tasks.some(task => task instanceof ScreenshotsTask)).toBe(false);
expect(tasks.some(task => task instanceof PreviewsTask)).toBe(true);
expect(tasks).toHaveLength(defaultTasks.length - 1);
});

it('omits the previews task when skipPreviews is enabled', () => {
const defaultTasks = createAppleTasks();
const tasks = createAppleTasks({ skipPreviews: true });

expect(tasks.some(task => task instanceof PreviewsTask)).toBe(false);
expect(tasks.some(task => task instanceof ScreenshotsTask)).toBe(true);
expect(tasks).toHaveLength(defaultTasks.length - 1);
});

it('omits both tasks when skipScreenshots and skipPreviews are enabled', () => {
const defaultTasks = createAppleTasks();
const tasks = createAppleTasks({ skipScreenshots: true, skipPreviews: true });

expect(tasks.some(task => task instanceof ScreenshotsTask)).toBe(false);
expect(tasks.some(task => task instanceof PreviewsTask)).toBe(false);
expect(tasks).toHaveLength(defaultTasks.length - 2);
});
});
22 changes: 20 additions & 2 deletions packages/eas-cli/src/metadata/apple/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ import { AppleTask } from '../task';

type AppleTaskOptions = {
version?: AppVersionOptions['version'];
/** If enabled, screenshots are not downloaded or uploaded */
skipScreenshots?: boolean;
/** If enabled, video previews are not downloaded or uploaded */
skipPreviews?: boolean;
};

/**
* List of all eligible tasks to sync local store configuration to the App store.
*/
export function createAppleTasks({ version }: AppleTaskOptions = {}): AppleTask[] {
return [
export function createAppleTasks({
version,
skipScreenshots,
skipPreviews,
}: AppleTaskOptions = {}): AppleTask[] {
const tasks = [
new AppVersionTask({ version }),
new AppInfoTask(),
new AgeRatingTask(),
Expand All @@ -24,4 +32,14 @@ export function createAppleTasks({ version }: AppleTaskOptions = {}): AppleTask[
new PreviewsTask(),
new AppClipTask(),
];

return tasks.filter(task => {
if (skipScreenshots && task instanceof ScreenshotsTask) {
return false;
}
if (skipPreviews && task instanceof PreviewsTask) {
return false;
}
return true;
});
}
6 changes: 5 additions & 1 deletion packages/eas-cli/src/metadata/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export async function downloadMetadataAsync({
nonInteractive,
graphqlClient,
projectId,
skipScreenshots = false,
skipPreviews = false,
}: {
projectDir: string;
profile: SubmitProfile;
Expand All @@ -37,6 +39,8 @@ export async function downloadMetadataAsync({
nonInteractive: boolean;
graphqlClient: ExpoGraphqlClient;
projectId: string;
skipScreenshots?: boolean;
skipPreviews?: boolean;
}): Promise<string> {
const filePath = getStaticConfigFilePath({ projectDir, profile });

Expand Down Expand Up @@ -76,7 +80,7 @@ export async function downloadMetadataAsync({

const errors: Error[] = [];
const config = createAppleWriter();
const tasks = createAppleTasks();
const tasks = createAppleTasks({ skipScreenshots, skipPreviews });
const taskCtx = { app, projectDir };

for (const task of tasks) {
Expand Down
6 changes: 6 additions & 0 deletions packages/eas-cli/src/metadata/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export async function uploadMetadataAsync({
nonInteractive,
graphqlClient,
projectId,
skipScreenshots = false,
skipPreviews = false,
}: {
projectDir: string;
profile: SubmitProfile;
Expand All @@ -36,6 +38,8 @@ export async function uploadMetadataAsync({
nonInteractive: boolean;
graphqlClient: ExpoGraphqlClient;
projectId: string;
skipScreenshots?: boolean;
skipPreviews?: boolean;
}): Promise<{ appleLink: string }> {
const storeConfig = await loadConfigWithValidationPromptAsync(
projectDir,
Expand Down Expand Up @@ -67,6 +71,8 @@ export async function uploadMetadataAsync({
// We need to resolve a different version as soon as possible.
// This version is the parent model of all changes we are going to push.
version: config.getVersion()?.versionString,
skipScreenshots,
skipPreviews,
});

const taskCtx = { app, projectDir };
Expand Down
Loading