From ca04ac63d606938e1a4ea1ca15a8bcda9e1cbe72 Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Fri, 5 Jan 2024 13:46:02 -0500 Subject: [PATCH] chore(shorebird_cli): only set aab channel if it is different (#1618) --- .../lib/src/commands/preview_command.dart | 27 +++- .../src/commands/preview_command_test.dart | 135 ++++++++++++++++++ 2 files changed, 155 insertions(+), 7 deletions(-) diff --git a/packages/shorebird_cli/lib/src/commands/preview_command.dart b/packages/shorebird_cli/lib/src/commands/preview_command.dart index bf0cb8ad..8805811f 100644 --- a/packages/shorebird_cli/lib/src/commands/preview_command.dart +++ b/packages/shorebird_cli/lib/src/commands/preview_command.dart @@ -19,6 +19,7 @@ import 'package:shorebird_cli/src/shorebird_env.dart'; import 'package:shorebird_cli/src/shorebird_validator.dart'; import 'package:shorebird_cli/src/third_party/flutter_tools/lib/flutter_tools.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; +import 'package:yaml/yaml.dart'; import 'package:yaml_edit/yaml_edit.dart'; /// {@template preview_command} @@ -445,15 +446,14 @@ class PreviewCommand extends ShorebirdCommand { await Isolate.run(() async { final tempDir = Directory.systemTemp.createTempSync(); - final basename = p.basenameWithoutExtension(aabFile.path); - final outputPath = p.join(tempDir.path, basename); + final outputPath = p.join(tempDir.path, 'tmp.aab'); await extractZip( zipFile: aabFile, outputDirectory: Directory(outputPath), ); - final shorebirdYaml = File( + final shorebirdYamlFile = File( p.join( outputPath, 'base', @@ -463,14 +463,27 @@ class PreviewCommand extends ShorebirdCommand { ), ); - if (!shorebirdYaml.existsSync()) { + if (!shorebirdYamlFile.existsSync()) { throw Exception('Unable to find shorebird.yaml'); } - final yaml = YamlEditor(shorebirdYaml.readAsStringSync()) - ..update(['channel'], channel); + final yamlText = shorebirdYamlFile.readAsStringSync(); + final yaml = loadYaml(yamlText) as YamlMap; + final yamlChannel = yaml['channel']; - shorebirdYaml.writeAsStringSync(yaml.toString(), flush: true); + if (yamlChannel == null && + channel == DeploymentTrack.production.channel) { + // We would be updating the channel to the default value. + return; + } + + if (yamlChannel == channel) { + // Updating this channel would be a no-op. + return; + } + + final yamlEditor = YamlEditor(yamlText)..update(['channel'], channel); + shorebirdYamlFile.writeAsStringSync(yamlEditor.toString(), flush: true); // This is equivalent to `zip --no-dir-entries` // Which does NOT create entries in the zip archive for directories. diff --git a/packages/shorebird_cli/test/src/commands/preview_command_test.dart b/packages/shorebird_cli/test/src/commands/preview_command_test.dart index 3afa96a3..eb1cb364 100644 --- a/packages/shorebird_cli/test/src/commands/preview_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/preview_command_test.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io' hide Platform; +import 'package:archive/archive_io.dart'; import 'package:args/args.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; @@ -371,6 +372,140 @@ void main() { }); }); + group('setChannelOnAab', () { + late File aabFile; + + File createAabFile({required String? channel}) { + final tempDir = Directory.systemTemp.createTempSync(); + final aabDirectory = Directory(p.join(tempDir.path, 'app-release')) + ..createSync(recursive: true); + final yamlContents = [ + 'app_id: $appId\n', + if (channel != null) 'channel: $channel\n', + ].join(); + File( + p.join( + aabDirectory.path, + 'base', + 'assets', + 'flutter_assets', + 'shorebird.yaml', + ), + ) + ..createSync(recursive: true) + ..writeAsStringSync(yamlContents); + + ZipFileEncoder().zipDirectory(aabDirectory, filename: aabPath()); + + return File(aabPath()); + } + + Future shorebirdYamlFileFromAab(File aab) async { + final tempDir = Directory.systemTemp.createTempSync(); + final aabDirectory = Directory(p.join(tempDir.path, 'app-release')) + ..createSync(recursive: true); + + await artifactManager.extractZip( + zipFile: aab, + outputDirectory: aabDirectory, + ); + return File( + p.join( + aabDirectory.path, + 'base', + 'assets', + 'flutter_assets', + 'shorebird.yaml', + ), + ); + } + + setUp(() { + artifactManager = ArtifactManager(); + }); + + group('when channel is not set', () { + group('when target channel is production', () { + test('does not change shorebird.yaml', () async { + aabFile = createAabFile(channel: null); + await runWithOverrides( + () => command.setChannelOnAab( + aabFile: aabFile, + channel: DeploymentTrack.production.channel, + ), + ); + + final updatedShorebirdYamlFile = + await shorebirdYamlFileFromAab(aabFile); + expect( + updatedShorebirdYamlFile.readAsStringSync(), + 'app_id: $appId\n', + ); + }); + }); + + group('when target channel is not production', () { + test('sets shorebird.yaml channel to target channel', () async { + aabFile = createAabFile(channel: null); + await runWithOverrides( + () => command.setChannelOnAab( + aabFile: aabFile, + channel: 'live', + ), + ); + + final updatedShorebirdYamlFile = + await shorebirdYamlFileFromAab(aabFile); + expect(updatedShorebirdYamlFile.readAsStringSync(), ''' +app_id: $appId +channel: live +'''); + }); + }); + }); + + group('when channel is set to target channel', () { + test('does not attempt to set channel', () async { + aabFile = createAabFile(channel: track.channel); + final originalModificationTime = aabFile.statSync().modified; + await runWithOverrides( + () => command.setChannelOnAab( + aabFile: aabFile, + channel: track.channel, + ), + ); + + final updatedShorebirdYamlFile = + await shorebirdYamlFileFromAab(aabFile); + expect(updatedShorebirdYamlFile.readAsStringSync(), ''' +app_id: $appId +channel: ${track.channel} +'''); + // Verify that we didn't touch the file. + expect(originalModificationTime, aabFile.statSync().modified); + }); + }); + + group('when channel is set to a different channel', () { + test('sets shorebird.yaml channel to target channel', () async { + aabFile = createAabFile(channel: 'dev'); + await runWithOverrides( + () => command.setChannelOnAab( + aabFile: aabFile, + channel: track.channel, + ), + ); + + final updatedShorebirdYamlFile = + await shorebirdYamlFileFromAab(aabFile); + expect(updatedShorebirdYamlFile.readAsStringSync(), ''' +app_id: $appId +channel: ${track.channel} +'''); + }); + }); + }); + test('exits with code 70 when querying for release artifact fails', () async { final exception = Exception('oops');