diff --git a/packages/shorebird_cli/lib/src/archive_analysis/aab_differ.dart b/packages/shorebird_cli/lib/src/archive_analysis/aab_differ.dart index f8ffca95..3994d28a 100644 --- a/packages/shorebird_cli/lib/src/archive_analysis/aab_differ.dart +++ b/packages/shorebird_cli/lib/src/archive_analysis/aab_differ.dart @@ -2,8 +2,10 @@ import 'dart:convert'; import 'dart:io'; import 'package:archive/archive_io.dart'; +import 'package:collection/collection.dart'; import 'package:shorebird_cli/src/archive_analysis/android_archive_differ.dart'; import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; +import 'package:shorebird_cli/src/archive_analysis/archive_differ.dart'; import 'package:shorebird_cli/src/archive_analysis/mf_reader.dart'; /// Finds differences between two AABs. @@ -45,10 +47,14 @@ class AabDiffer extends AndroidArchiveDiffer { String _metaInfMfContent(File aab) { final inputStream = InputFileStream(aab.path); final archive = ZipDecoder().decodeBuffer(inputStream); - return utf8.decode( - archive.files - .firstWhere((file) => file.name == 'META-INF/MANIFEST.MF') - .content as List, + final manifestFile = archive.files.firstWhereOrNull( + (file) => file.name == 'META-INF/MANIFEST.MF', ); + + if (manifestFile == null) { + throw DiffFailedException(); + } + + return utf8.decode(manifestFile.content as List); } } diff --git a/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart b/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart index ad10f384..760a15d8 100644 --- a/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart +++ b/packages/shorebird_cli/lib/src/archive_analysis/archive_differ.dart @@ -1,5 +1,8 @@ import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; +/// Thrown when an [ArchiveDiffer] fails to generate a [FileSetDiff]. +class DiffFailedException implements Exception {} + /// Computes content differences between two archives. abstract class ArchiveDiffer { /// Files that have been added, removed, or that have changed between the diff --git a/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart b/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart index b15a79ba..dba1c582 100644 --- a/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart +++ b/packages/shorebird_cli/lib/src/commands/patch/patch_android_command.dart @@ -5,6 +5,7 @@ import 'package:http/http.dart' as http; import 'package:mason_logger/mason_logger.dart'; import 'package:path/path.dart' as p; import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; +import 'package:shorebird_cli/src/archive_analysis/archive_differ.dart'; import 'package:shorebird_cli/src/cache.dart'; import 'package:shorebird_cli/src/code_push_client_wrapper.dart'; import 'package:shorebird_cli/src/command.dart'; @@ -242,10 +243,19 @@ https://github.com/shorebirdtech/shorebird/issues/472 downloadReleaseArtifactProgress.complete(); - final contentDiffs = _aabDiffer.changedFiles( - releaseAabPath, - bundlePath, - ); + FileSetDiff contentDiffs; + try { + contentDiffs = _aabDiffer.changedFiles( + releaseAabPath, + bundlePath, + ); + } on DiffFailedException catch (_) { + logger.warn( + ''' +Could not determine whether patch contains asset changes. If you have added or removed assets, you will need to create a new release.''', + ); + contentDiffs = FileSetDiff.empty(); + } logger.detail('aab content differences: $contentDiffs'); diff --git a/packages/shorebird_cli/test/fixtures/aabs/no_manifest.aab b/packages/shorebird_cli/test/fixtures/aabs/no_manifest.aab new file mode 100644 index 00000000..11827d0e Binary files /dev/null and b/packages/shorebird_cli/test/fixtures/aabs/no_manifest.aab differ diff --git a/packages/shorebird_cli/test/src/archive_analysis/aab_differ_test.dart b/packages/shorebird_cli/test/src/archive_analysis/aab_differ_test.dart index 52ff09fe..9ba8a09e 100644 --- a/packages/shorebird_cli/test/src/archive_analysis/aab_differ_test.dart +++ b/packages/shorebird_cli/test/src/archive_analysis/aab_differ_test.dart @@ -1,5 +1,6 @@ import 'package:path/path.dart' as p; import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; +import 'package:shorebird_cli/src/archive_analysis/archive_differ.dart'; import 'package:test/test.dart'; void main() { @@ -13,6 +14,7 @@ void main() { p.join(aabFixturesBasePath, 'changed_kotlin.aab'); final changedDartAndAssetAabPath = p.join(aabFixturesBasePath, 'changed_dart_and_asset.aab'); + final noManifestAabPath = p.join(aabFixturesBasePath, 'no_manifest.aab'); late AabDiffer differ; @@ -38,6 +40,13 @@ void main() { }); }); + test('does not crash if MANIFEST.MF is missing', () { + expect( + () => differ.changedFiles(baseAabPath, noManifestAabPath), + throwsA(isA()), + ); + }); + group('contentDifferences', () { test('detects no differences between the same aab', () { expect(differ.changedFiles(baseAabPath, baseAabPath), isEmpty); diff --git a/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart b/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart index 0787d3ab..31752fc6 100644 --- a/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/patch/patch_android_command_test.dart @@ -8,6 +8,7 @@ import 'package:path/path.dart' as p; import 'package:platform/platform.dart'; import 'package:scoped/scoped.dart'; import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart'; +import 'package:shorebird_cli/src/archive_analysis/archive_differ.dart'; import 'package:shorebird_cli/src/auth/auth.dart'; import 'package:shorebird_cli/src/bundletool.dart'; import 'package:shorebird_cli/src/cache.dart' show Cache, cacheRef; @@ -622,6 +623,27 @@ https://github.com/shorebirdtech/shorebird/issues/472 expect(exitCode, ExitCode.software.code); }); + test( + 'prints warning if differ cannot determine patch differences', + () async { + when(() => aabDiffer.changedFiles(any(), any())) + .thenThrow(DiffFailedException()); + final tempDir = setUpTempDir(); + setUpTempArtifacts(tempDir); + final exitCode = await IOOverrides.runZoned( + () => runWithOverrides(command.run), + getCurrentDirectory: () => tempDir, + ); + + expect(exitCode, ExitCode.success.code); + verify( + () => logger.warn( + '''Could not determine whether patch contains asset changes. If you have added or removed assets, you will need to create a new release.''', + ), + ).called(1); + }, + ); + test('prompts user to continue when Java/Kotlin code changes are detected', () async { when(() => aabDiffer.containsPotentiallyBreakingNativeDiffs(any()))