diff --git a/CHANGELOG.md b/CHANGELOG.md index a695366585..47e878f61a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/packages/eas-cli/README.md b/packages/eas-cli/README.md index 239a8bb5e0..b3601c3ff5 100644 --- a/packages/eas-cli/README.md +++ b/packages/eas-cli/README.md @@ -1875,11 +1875,13 @@ generate the local store configuration from the app stores ``` USAGE - $ eas metadata:pull [-e ] [--non-interactive] + $ eas metadata:pull [-e ] [--skip-screenshots] [--skip-previews] [--non-interactive] FLAGS - -e, --profile= 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= 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 @@ -1893,11 +1895,14 @@ sync the local store configuration to the app stores ``` USAGE - $ eas metadata:push [-e ] [--non-interactive] + $ eas metadata:push [-e ] [--skip-screenshots] [--skip-previews] [--non-interactive] FLAGS - -e, --profile= 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= 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 diff --git a/packages/eas-cli/src/commands/metadata/pull.ts b/packages/eas-cli/src/commands/metadata/pull.ts index dcd1e0fed7..7843e54e44 100644 --- a/packages/eas-cli/src/commands/metadata/pull.ts +++ b/packages/eas-cli/src/commands/metadata/pull.ts @@ -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, }; @@ -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({ @@ -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); diff --git a/packages/eas-cli/src/commands/metadata/push.ts b/packages/eas-cli/src/commands/metadata/push.ts index a41046a33a..5c59762d03 100644 --- a/packages/eas-cli/src/commands/metadata/push.ts +++ b/packages/eas-cli/src/commands/metadata/push.ts @@ -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, }; @@ -80,6 +89,8 @@ export default class MetadataPush extends EasCommand { nonInteractive, graphqlClient, projectId, + skipScreenshots: flags['skip-screenshots'], + skipPreviews: flags['skip-previews'], }); Log.addNewLineIfNone(); diff --git a/packages/eas-cli/src/metadata/__tests__/download.test.ts b/packages/eas-cli/src/metadata/__tests__/download.test.ts index 97b18bb146..c36fea576b 100644 --- a/packages/eas-cli/src/metadata/__tests__/download.test.ts +++ b/packages/eas-cli/src/metadata/__tests__/download.test.ts @@ -40,6 +40,9 @@ jest.mock('../../prompts', () => ({ })); const { confirmAsync } = require('../../prompts') as jest.Mocked; +const { createAppleTasks } = require('../apple/tasks') as jest.Mocked< + typeof import('../apple/tasks') +>; function createArgs(overrides: Record = {}) { return { @@ -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 })); + }); }); diff --git a/packages/eas-cli/src/metadata/__tests__/upload.test.ts b/packages/eas-cli/src/metadata/__tests__/upload.test.ts index 9001239e89..ab068a799c 100644 --- a/packages/eas-cli/src/metadata/__tests__/upload.test.ts +++ b/packages/eas-cli/src/metadata/__tests__/upload.test.ts @@ -36,6 +36,9 @@ const { loadConfigAsync } = require('../config/resolve') as jest.Mocked< typeof import('../config/resolve') >; const { confirmAsync } = require('../../prompts') as jest.Mocked; +const { createAppleTasks } = require('../apple/tasks') as jest.Mocked< + typeof import('../apple/tasks') +>; function createArgs(overrides: Record = {}) { return { @@ -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 })); + }); }); diff --git a/packages/eas-cli/src/metadata/apple/tasks/__tests__/index.test.ts b/packages/eas-cli/src/metadata/apple/tasks/__tests__/index.test.ts new file mode 100644 index 0000000000..256171a6f8 --- /dev/null +++ b/packages/eas-cli/src/metadata/apple/tasks/__tests__/index.test.ts @@ -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); + }); +}); diff --git a/packages/eas-cli/src/metadata/apple/tasks/index.ts b/packages/eas-cli/src/metadata/apple/tasks/index.ts index 06fadbdf01..4c87cfd465 100644 --- a/packages/eas-cli/src/metadata/apple/tasks/index.ts +++ b/packages/eas-cli/src/metadata/apple/tasks/index.ts @@ -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(), @@ -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; + }); } diff --git a/packages/eas-cli/src/metadata/download.ts b/packages/eas-cli/src/metadata/download.ts index a748eb3791..90ad9aeea1 100644 --- a/packages/eas-cli/src/metadata/download.ts +++ b/packages/eas-cli/src/metadata/download.ts @@ -28,6 +28,8 @@ export async function downloadMetadataAsync({ nonInteractive, graphqlClient, projectId, + skipScreenshots = false, + skipPreviews = false, }: { projectDir: string; profile: SubmitProfile; @@ -37,6 +39,8 @@ export async function downloadMetadataAsync({ nonInteractive: boolean; graphqlClient: ExpoGraphqlClient; projectId: string; + skipScreenshots?: boolean; + skipPreviews?: boolean; }): Promise { const filePath = getStaticConfigFilePath({ projectDir, profile }); @@ -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) { diff --git a/packages/eas-cli/src/metadata/upload.ts b/packages/eas-cli/src/metadata/upload.ts index c0290b27e8..8b23781359 100644 --- a/packages/eas-cli/src/metadata/upload.ts +++ b/packages/eas-cli/src/metadata/upload.ts @@ -27,6 +27,8 @@ export async function uploadMetadataAsync({ nonInteractive, graphqlClient, projectId, + skipScreenshots = false, + skipPreviews = false, }: { projectDir: string; profile: SubmitProfile; @@ -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, @@ -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 };