diff --git a/packages/shorebird_code_push_client/lib/src/code_push_client.dart b/packages/shorebird_code_push_client/lib/src/code_push_client.dart index ef573669..aa16a12b 100644 --- a/packages/shorebird_code_push_client/lib/src/code_push_client.dart +++ b/packages/shorebird_code_push_client/lib/src/code_push_client.dart @@ -213,6 +213,20 @@ class CodePushClient { return Release.fromJson(body); } + /// Remove [userId] as a collaborator from [appId]. + Future deleteAppCollaborator({ + required String appId, + required int userId, + }) async { + final response = await _httpClient.delete( + Uri.parse('$hostedUri/api/v1/apps/$appId/collaborators/$userId'), + ); + + if (response.statusCode != HttpStatus.noContent) { + throw _parseErrorResponse(response.body); + } + } + /// Delete the release with the provided [releaseId]. Future deleteRelease({required int releaseId}) async { final response = await _httpClient.delete( diff --git a/packages/shorebird_code_push_client/test/src/code_push_client_test.dart b/packages/shorebird_code_push_client/test/src/code_push_client_test.dart index da2550c6..ac3befe7 100644 --- a/packages/shorebird_code_push_client/test/src/code_push_client_test.dart +++ b/packages/shorebird_code_push_client/test/src/code_push_client_test.dart @@ -871,6 +871,80 @@ void main() { }); }); + group('deleteAppCollaborator', () { + const appId = 'test-app-id'; + const userId = 42; + + test('throws an exception if the http request fails (unknown)', () async { + when( + () => httpClient.delete(any(), headers: any(named: 'headers')), + ).thenAnswer( + (_) async => http.Response('', HttpStatus.failedDependency), + ); + + expect( + codePushClient.deleteAppCollaborator(appId: appId, userId: userId), + throwsA( + isA().having( + (e) => e.message, + 'message', + CodePushClient.unknownErrorMessage, + ), + ), + ); + }); + + test('throws an exception if the http request fails', () async { + when( + () => httpClient.delete(any(), headers: any(named: 'headers')), + ).thenAnswer( + (_) async => http.Response( + json.encode(errorResponse.toJson()), + HttpStatus.failedDependency, + ), + ); + + expect( + codePushClient.deleteAppCollaborator(appId: appId, userId: userId), + throwsA( + isA().having( + (e) => e.message, + 'message', + errorResponse.message, + ), + ), + ); + }); + + test('completes when request succeeds', () async { + when( + () => httpClient.delete( + any(), + headers: any(named: 'headers'), + ), + ).thenAnswer((_) async => http.Response('', HttpStatus.noContent)); + + await codePushClient.deleteAppCollaborator( + appId: appId, + userId: userId, + ); + + final uri = verify( + () => httpClient.delete( + captureAny(), + headers: any(named: 'headers'), + ), + ).captured.single as Uri; + + expect( + uri, + codePushClient.hostedUri.replace( + path: '/api/v1/apps/$appId/collaborators/$userId', + ), + ); + }); + }); + group('deleteRelease', () { const releaseId = 42;