diff --git a/packages/shorebird_cli/lib/src/executables/git.dart b/packages/shorebird_cli/lib/src/executables/git.dart index 6578be63..c9372786 100644 --- a/packages/shorebird_cli/lib/src/executables/git.dart +++ b/packages/shorebird_cli/lib/src/executables/git.dart @@ -87,6 +87,29 @@ class Git { } } + /// Run `git remote` at [directory]. + // TODO(eseidel): add a generic `git` method for running arbitrary git + // commands and removing duplication between these methods. + Future remote({ + required String directory, + List? args, + }) async { + final arguments = ['remote', ...?args]; + final result = await process.run( + executable, + arguments, + workingDirectory: directory, + ); + if (result.exitCode != 0) { + throw ProcessException( + executable, + arguments, + '${result.stderr}', + result.exitCode, + ); + } + } + /// Iterate over all refs that match [pattern] and show them /// according to the given [format]. Future forEachRef({ diff --git a/packages/shorebird_cli/lib/src/shorebird_version.dart b/packages/shorebird_cli/lib/src/shorebird_version.dart index 31c81495..3d725599 100644 --- a/packages/shorebird_cli/lib/src/shorebird_version.dart +++ b/packages/shorebird_cli/lib/src/shorebird_version.dart @@ -28,6 +28,9 @@ class ShorebirdVersion { /// /// Exits if HEAD isn't pointing to a branch, or there is no upstream. Future fetchLatestGitHash() async { + // Dependabot pushed branches with the same name breaking all clients + // and requiring a prune to repair them. + await git.remote(directory: _workingDirectory, args: ['prune', 'origin']); // Fetch upstream branch's commits and tags await git.fetch(directory: _workingDirectory, args: ['--tags']); // Get the latest commit revision of the upstream diff --git a/packages/shorebird_cli/test/src/executables/git_test.dart b/packages/shorebird_cli/test/src/executables/git_test.dart index 359ae338..e2478945 100644 --- a/packages/shorebird_cli/test/src/executables/git_test.dart +++ b/packages/shorebird_cli/test/src/executables/git_test.dart @@ -328,6 +328,58 @@ origin/flutter_release/3.10.6'''; }); }); + group('remote', () { + const directory = './output'; + + test('executes correct command', () async { + await expectLater( + runWithOverrides( + () => git.remote(directory: directory), + ), + completes, + ); + verify( + () => process.run( + 'git', + ['remote'], + workingDirectory: directory, + ), + ).called(1); + }); + + test('executes correct command w/args', () async { + const args = ['prune', 'origin']; + await expectLater( + runWithOverrides( + () => git.remote( + directory: directory, + args: args, + ), + ), + completes, + ); + verify( + () => process.run( + 'git', + ['remote', ...args], + workingDirectory: directory, + ), + ).called(1); + }); + + test('throws ProcessException if process exits with error', () async { + const error = 'oops'; + when(() => processResult.exitCode).thenReturn(ExitCode.software.code); + when(() => processResult.stderr).thenReturn(error); + expect( + () => runWithOverrides(() => git.remote(directory: directory)), + throwsA( + isA().having((e) => e.message, 'message', error), + ), + ); + }); + }); + group('revParse', () { const directory = './output'; const revision = 'revision'; diff --git a/packages/shorebird_cli/test/src/shorebird_version_test.dart b/packages/shorebird_cli/test/src/shorebird_version_test.dart index 02ef8f2b..a101340e 100644 --- a/packages/shorebird_cli/test/src/shorebird_version_test.dart +++ b/packages/shorebird_cli/test/src/shorebird_version_test.dart @@ -36,6 +36,12 @@ void main() { args: any(named: 'args'), ), ).thenAnswer((_) async => {}); + when( + () => git.remote( + directory: any(named: 'directory'), + args: any(named: 'args'), + ), + ).thenAnswer((_) async => {}); when( () => git.revParse( revision: any(named: 'revision'),