diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fbff8ec5c..8d14e79920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This is the log of notable changes to EAS CLI and related packages. ### 🐛 Bug fixes +- [eas-cli] Remove temporary working directories after `eas build:inspect` copies inspect output, avoiding leftover disk usage after failed builds. ([#3981](https://github.com/expo/eas-cli/pull/3981) by [@szdziedzic](https://github.com/szdziedzic)) - [build-tools] Skip embedded bundle upload for development client builds instead of warning that the bundle is missing. ([#3940](https://github.com/expo/eas-cli/pull/3940) by [@gwdp](https://github.com/gwdp)) - [eas-cli] Retry uploading assets that don't finish processing during `eas update`, instead of failing the update. ([#3918](https://github.com/expo/eas-cli/pull/3918) by [@gwdp](https://github.com/gwdp)) diff --git a/packages/eas-cli/src/commands/build/__tests__/inspect.test.ts b/packages/eas-cli/src/commands/build/__tests__/inspect.test.ts new file mode 100644 index 0000000000..ac9da381d8 --- /dev/null +++ b/packages/eas-cli/src/commands/build/__tests__/inspect.test.ts @@ -0,0 +1,92 @@ +import fs from 'fs-extra'; +import path from 'path'; + +import { getMockOclifConfig } from '../../../__tests__/commands/utils'; +import { runBuildAndSubmitAsync } from '../../../build/runBuildAndSubmit'; +import BuildInspect from '../inspect'; + +jest.mock('fs-extra', () => ({ + pathExists: jest.fn(), + remove: jest.fn(), + mkdirp: jest.fn(), + copy: jest.fn(), +})); +jest.mock('../../../build/runBuildAndSubmit', () => ({ + runBuildAndSubmitAsync: jest.fn(), +})); +jest.mock('../../../log'); +jest.mock('../../../ora', () => ({ + ora: jest.fn(() => ({ + start: jest.fn(() => ({ + succeed: jest.fn(), + fail: jest.fn(), + })), + })), +})); +jest.mock('../../../utils/paths', () => ({ + ...jest.requireActual('../../../utils/paths'), + getTmpDirectory: jest.fn(() => '/tmp/eas-cli'), +})); +jest.mock('uuid', () => ({ + v4: jest.fn(() => 'tmp-id'), +})); + +describe(BuildInspect, () => { + const mockConfig = getMockOclifConfig(); + const tmpWorkingdir = '/tmp/eas-cli/tmp-id'; + const tmpBuildDir = path.join(tmpWorkingdir, 'build'); + const outputDirectory = path.join(process.cwd(), 'inspect-output'); + const mockPathExists = fs.pathExists as jest.Mock; + const mockMkdirp = fs.mkdirp as jest.Mock; + const mockCopy = fs.copy as jest.Mock; + const mockRemove = fs.remove as jest.Mock; + + beforeEach(() => { + jest.clearAllMocks(); + mockPathExists.mockResolvedValue(false); + mockMkdirp.mockResolvedValue(undefined); + mockCopy.mockResolvedValue(undefined); + mockRemove.mockResolvedValue(undefined); + jest.mocked(runBuildAndSubmitAsync).mockResolvedValue({ buildIds: [] }); + }); + + function createCommand(): BuildInspect { + const command = new BuildInspect( + ['--platform', 'ios', '--stage', 'pre-build', '--output', 'inspect-output'], + mockConfig + ); + jest.spyOn(command as any, 'getContextAsync').mockResolvedValue({ + loggedIn: { + actor: {}, + graphqlClient: {}, + }, + getDynamicPrivateProjectConfigAsync: jest.fn(), + projectDir: '/project', + analytics: {}, + vcsClient: {}, + } as any); + return command; + } + + it('removes the temporary working directory after copying output when the build fails', async () => { + jest.mocked(runBuildAndSubmitAsync).mockRejectedValue(new Error('build failed')); + mockPathExists.mockResolvedValueOnce(false).mockResolvedValueOnce(true); + + await createCommand().runAsync(); + + expect(fs.copy).toHaveBeenCalledWith(tmpBuildDir, outputDirectory); + expect(fs.remove).toHaveBeenCalledWith(tmpBuildDir); + expect(fs.remove).toHaveBeenCalledWith(tmpWorkingdir); + }); + + it('keeps the temporary working directory when copying output fails', async () => { + jest.mocked(runBuildAndSubmitAsync).mockRejectedValue(new Error('build failed')); + mockPathExists.mockResolvedValueOnce(false).mockResolvedValueOnce(true); + mockCopy.mockRejectedValue(new Error('copy failed')); + + await expect(createCommand().runAsync()).rejects.toThrow('copy failed'); + + expect(fs.remove).not.toHaveBeenCalledWith(tmpBuildDir); + expect(fs.remove).not.toHaveBeenCalledWith(tmpWorkingdir); + }); +}); diff --git a/packages/eas-cli/src/commands/build/inspect.ts b/packages/eas-cli/src/commands/build/inspect.ts index 5e805e2bda..6b9c883196 100644 --- a/packages/eas-cli/src/commands/build/inspect.ts +++ b/packages/eas-cli/src/commands/build/inspect.ts @@ -135,6 +135,7 @@ export default class BuildInspect extends EasCommand { } } finally { await this.copyToOutputDirAsync(path.join(tmpWorkingdir, 'build'), outputDirectory); + await this.cleanUpTmpWorkingdirAsync(tmpWorkingdir); } } } @@ -163,4 +164,13 @@ export default class BuildInspect extends EasCommand { throw err; } } + + private async cleanUpTmpWorkingdirAsync(tmpWorkingdir: string): Promise { + try { + await fs.remove(tmpWorkingdir); + } catch (err) { + Log.warn(`Failed to remove temporary directory ${tmpWorkingdir}`); + Log.debug(err); + } + } }