mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-27 01:02:14 +08:00
GitHostApis: Use Result class
Instead of throwing exceptions. There are so so many edge cases which are failing.
This commit is contained in:
@ -16,22 +16,32 @@ class GitHubFake implements GitHost {
|
||||
Future launchOAuthScreen() async {}
|
||||
|
||||
@override
|
||||
Future<UserInfo?> getUserInfo() async {}
|
||||
@override
|
||||
Future addDeployKey(String sshPublicKey, String repoFullName) async {}
|
||||
|
||||
@override
|
||||
Future<GitHostRepo> createRepo(String name) async {
|
||||
return GitHub.repoFromJson({});
|
||||
Future<Result<UserInfo>> getUserInfo() async {
|
||||
var ex = Exception("Not Implemented");
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GitHostRepo> getRepo(String name) async {
|
||||
return GitHub.repoFromJson({});
|
||||
Future<Result<void>> addDeployKey(
|
||||
String sshPublicKey, String repoFullName) async {
|
||||
var ex = Exception("Not Implemented");
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GitHostRepo>> listRepos() async {
|
||||
Future<Result<GitHostRepo>> createRepo(String name) async {
|
||||
var ex = Exception("Not Implemented");
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<GitHostRepo>> getRepo(String name) async {
|
||||
var ex = Exception("Not Implemented");
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Result<List<GitHostRepo>>> listRepos() async {
|
||||
List<dynamic> list = jsonDecode(data);
|
||||
var repos = <GitHostRepo>[];
|
||||
list.forEach((dynamic d) {
|
||||
@ -40,6 +50,6 @@ class GitHubFake implements GitHost {
|
||||
repos.add(repo);
|
||||
});
|
||||
|
||||
return repos;
|
||||
return Result(repos);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dart_git/utils/result.dart';
|
||||
|
||||
export 'package:dart_git/utils/result.dart';
|
||||
|
||||
typedef OAuthCallback = void Function(GitHostException?);
|
||||
|
||||
@ -8,11 +11,11 @@ abstract class GitHost {
|
||||
void init(OAuthCallback oAuthCallback);
|
||||
Future launchOAuthScreen();
|
||||
|
||||
Future<UserInfo?> getUserInfo();
|
||||
Future<List<GitHostRepo>> listRepos();
|
||||
Future<GitHostRepo> createRepo(String name);
|
||||
Future<GitHostRepo> getRepo(String name);
|
||||
Future addDeployKey(String sshPublicKey, String repoFullName);
|
||||
Future<Result<UserInfo>> getUserInfo();
|
||||
Future<Result<List<GitHostRepo>>> listRepos();
|
||||
Future<Result<GitHostRepo>> createRepo(String name);
|
||||
Future<Result<GitHostRepo>> getRepo(String name);
|
||||
Future<Result<void>> addDeployKey(String sshPublicKey, String repoFullName);
|
||||
}
|
||||
|
||||
class UserInfo {
|
||||
@ -99,6 +102,8 @@ class GitHostException implements Exception {
|
||||
static const CreateRepoFailed = GitHostException("CreateRepoFailed");
|
||||
static const DeployKeyFailed = GitHostException("DeployKeyFailed");
|
||||
static const GetRepoFailed = GitHostException("GetRepoFailed");
|
||||
static const HttpResponseFail = GitHostException("HttpResponseFail");
|
||||
static const JsonDecodingFail = GitHostException("JsonDecodingFail");
|
||||
|
||||
final String cause;
|
||||
const GitHostException(this.cause);
|
||||
|
@ -11,6 +11,8 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:gitjournal/utils/logger.dart';
|
||||
import 'githost.dart';
|
||||
|
||||
// FIXME: Handle for edge cases of json.decode
|
||||
|
||||
class GitHub implements GitHost {
|
||||
static const _clientID = "aa3072cbfb02b1db14ed";
|
||||
static const _clientSecret = "010d303ea99f82330f2b228977cef9ddbf7af2cd";
|
||||
@ -79,9 +81,10 @@ class GitHub implements GitHost {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GitHostRepo>> listRepos() async {
|
||||
Future<Result<List<GitHostRepo>>> listRepos() async {
|
||||
if (_accessCode.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var url =
|
||||
@ -96,11 +99,12 @@ class GitHub implements GitHost {
|
||||
|
||||
var response = await http.get(url, headers: headers);
|
||||
if (response.statusCode != 200) {
|
||||
Log.d("Github listRepos: Invalid response " +
|
||||
Log.e("Github listRepos: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
return [];
|
||||
var ex = GitHostException.HttpResponseFail;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
List<dynamic> list = jsonDecode(response.body);
|
||||
@ -112,13 +116,14 @@ class GitHub implements GitHost {
|
||||
});
|
||||
|
||||
// FIXME: Sort these based on some criteria
|
||||
return repos;
|
||||
return Result(repos);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GitHostRepo> createRepo(String name) async {
|
||||
Future<Result<GitHostRepo>> createRepo(String name) async {
|
||||
if (_accessCode.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var url = Uri.parse("https://api.github.com/user/repos");
|
||||
@ -135,35 +140,39 @@ class GitHub implements GitHost {
|
||||
var response =
|
||||
await http.post(url, headers: headers, body: json.encode(data));
|
||||
if (response.statusCode != 201) {
|
||||
Log.d("Github createRepo: Invalid response " +
|
||||
Log.e("Github createRepo: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
|
||||
if (response.statusCode == 422) {
|
||||
if (response.body.contains("name already exists")) {
|
||||
throw GitHostException.RepoExists;
|
||||
var ex = GitHostException.RepoExists;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
throw GitHostException.CreateRepoFailed;
|
||||
var ex = GitHostException.CreateRepoFailed;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Log.d("GitHub createRepo: " + response.body);
|
||||
Map<String, dynamic> map = json.decode(response.body);
|
||||
return repoFromJson(map);
|
||||
return Result(repoFromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GitHostRepo> getRepo(String name) async {
|
||||
Future<Result<GitHostRepo>> getRepo(String name) async {
|
||||
if (_accessCode.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var userInfo = await getUserInfo();
|
||||
if (userInfo == null) {
|
||||
throw Exception("GitHub UserInfo not found. This is bad");
|
||||
var userInfoR = await getUserInfo();
|
||||
if (userInfoR.isFailure) {
|
||||
return fail(userInfoR);
|
||||
}
|
||||
var userInfo = userInfoR.getOrThrow();
|
||||
var owner = userInfo.username;
|
||||
var url = Uri.parse("https://api.github.com/repos/$owner/$name");
|
||||
|
||||
@ -173,23 +182,29 @@ class GitHub implements GitHost {
|
||||
|
||||
var response = await http.get(url, headers: headers);
|
||||
if (response.statusCode != 200) {
|
||||
Log.d("Github getRepo: Invalid response " +
|
||||
Log.e("Github getRepo: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
|
||||
throw GitHostException.GetRepoFailed;
|
||||
var ex = GitHostException.GetRepoFailed;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Log.d("GitHub getRepo: " + response.body);
|
||||
try {
|
||||
Map<String, dynamic> map = json.decode(response.body);
|
||||
return repoFromJson(map);
|
||||
return Result(repoFromJson(map));
|
||||
} on Exception catch (ex, st) {
|
||||
return Result.fail(ex, st);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future addDeployKey(String sshPublicKey, String repo) async {
|
||||
Future<Result<void>> addDeployKey(String sshPublicKey, String repo) async {
|
||||
if (_accessCode.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var url = Uri.parse("https://api.github.com/repos/$repo/keys");
|
||||
@ -212,11 +227,12 @@ class GitHub implements GitHost {
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
throw GitHostException.DeployKeyFailed;
|
||||
var ex = GitHostException.DeployKeyFailed;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Log.d("GitHub addDeployKey: " + response.body);
|
||||
return json.decode(response.body);
|
||||
return Result(null);
|
||||
}
|
||||
|
||||
static GitHostRepo repoFromJson(Map<String, dynamic> parsedJson) {
|
||||
@ -261,9 +277,10 @@ class GitHub implements GitHost {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserInfo?> getUserInfo() async {
|
||||
Future<Result<UserInfo>> getUserInfo() async {
|
||||
if (_accessCode.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var url = Uri.parse("https://api.github.com/user");
|
||||
@ -278,7 +295,8 @@ class GitHub implements GitHost {
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
return null;
|
||||
var ex = GitHostException.HttpResponseFail;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Map<String, dynamic>? map = jsonDecode(response.body);
|
||||
@ -287,14 +305,16 @@ class GitHub implements GitHost {
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
return null;
|
||||
|
||||
var ex = GitHostException.JsonDecodingFail;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
return UserInfo(
|
||||
return Result(UserInfo(
|
||||
name: map['name'],
|
||||
email: map['email'],
|
||||
username: map['login'],
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
String _buildAuthHeader() {
|
||||
|
@ -12,6 +12,8 @@ import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:gitjournal/utils/logger.dart';
|
||||
import 'githost.dart';
|
||||
|
||||
// FIXME: Handle for edge cases of json.decode
|
||||
|
||||
class GitLab implements GitHost {
|
||||
static const _clientID =
|
||||
"faf33c3716faf05bfb701b1b31e36c83a23c3ec2d7161f4ff00fba2275524d09";
|
||||
@ -67,9 +69,10 @@ class GitLab implements GitHost {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GitHostRepo>> listRepos() async {
|
||||
Future<Result<List<GitHostRepo>>> listRepos() async {
|
||||
if (_accessCode!.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
// FIXME: pagination!
|
||||
@ -82,11 +85,12 @@ class GitLab implements GitHost {
|
||||
|
||||
var response = await http.get(url);
|
||||
if (response.statusCode != 200) {
|
||||
Log.d("GitLab listRepos: Invalid response " +
|
||||
Log.e("GitLab listRepos: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
return [];
|
||||
var ex = GitHostException.HttpResponseFail;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
List<dynamic> list = jsonDecode(response.body);
|
||||
@ -98,13 +102,14 @@ class GitLab implements GitHost {
|
||||
});
|
||||
|
||||
// FIXME: Sort these based on some criteria
|
||||
return repos;
|
||||
return Result(repos);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GitHostRepo> createRepo(String name) async {
|
||||
Future<Result<GitHostRepo>> createRepo(String name) async {
|
||||
if (_accessCode!.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var url = Uri.parse(
|
||||
@ -121,58 +126,64 @@ class GitLab implements GitHost {
|
||||
var response =
|
||||
await http.post(url, headers: headers, body: json.encode(data));
|
||||
if (response.statusCode != 201) {
|
||||
Log.d("GitLab createRepo: Invalid response " +
|
||||
Log.e("GitLab createRepo: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
if (response.body.contains("has already been taken")) {
|
||||
throw GitHostException.RepoExists;
|
||||
var ex = GitHostException.RepoExists;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
throw GitHostException.CreateRepoFailed;
|
||||
var ex = GitHostException.CreateRepoFailed;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Log.d("GitLab createRepo: " + response.body);
|
||||
Map<String, dynamic> map = json.decode(response.body);
|
||||
return repoFromJson(map);
|
||||
return Result(repoFromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GitHostRepo> getRepo(String name) async {
|
||||
Future<Result<GitHostRepo>> getRepo(String name) async {
|
||||
if (_accessCode!.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var userInfo = await getUserInfo();
|
||||
if (userInfo == null) {
|
||||
throw Exception("GitLab no userInfo found!!");
|
||||
var userInfoR = await getUserInfo();
|
||||
if (userInfoR.isFailure) {
|
||||
return fail(userInfoR);
|
||||
}
|
||||
var userInfo = userInfoR.getOrThrow();
|
||||
var repo = userInfo.username + '%2F' + name;
|
||||
var url = Uri.parse(
|
||||
"https://gitlab.com/api/v4/projects/$repo?access_token=$_accessCode");
|
||||
|
||||
var response = await http.get(url);
|
||||
if (response.statusCode != 200) {
|
||||
Log.d("GitLab getRepo: Invalid response " +
|
||||
Log.e("GitLab getRepo: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
|
||||
throw GitHostException.GetRepoFailed;
|
||||
var ex = GitHostException.GetRepoFailed;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Log.d("GitLab getRepo: " + response.body);
|
||||
Map<String, dynamic> map = json.decode(response.body);
|
||||
return repoFromJson(map);
|
||||
return Result(repoFromJson(map));
|
||||
}
|
||||
|
||||
@override
|
||||
Future addDeployKey(String sshPublicKey, String repo) async {
|
||||
Future<Result<void>> addDeployKey(String sshPublicKey, String repo) async {
|
||||
if (_accessCode!.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
repo = repo.replaceAll('/', '%2F');
|
||||
@ -192,15 +203,16 @@ class GitLab implements GitHost {
|
||||
var response =
|
||||
await http.post(url, headers: headers, body: json.encode(data));
|
||||
if (response.statusCode != 201) {
|
||||
Log.d("GitLab addDeployKey: Invalid response " +
|
||||
Log.e("GitLab addDeployKey: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
throw GitHostException.DeployKeyFailed;
|
||||
var ex = GitHostException.DeployKeyFailed;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Log.d("GitLab addDeployKey: " + response.body);
|
||||
return json.decode(response.body);
|
||||
return Result(null);
|
||||
}
|
||||
|
||||
static GitHostRepo repoFromJson(Map<String, dynamic> parsedJson) {
|
||||
@ -245,9 +257,10 @@ class GitLab implements GitHost {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserInfo?> getUserInfo() async {
|
||||
Future<Result<UserInfo>> getUserInfo() async {
|
||||
if (_accessCode!.isEmpty) {
|
||||
throw GitHostException.MissingAccessCode;
|
||||
var ex = GitHostException.MissingAccessCode;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
var url =
|
||||
@ -255,27 +268,31 @@ class GitLab implements GitHost {
|
||||
|
||||
var response = await http.get(url);
|
||||
if (response.statusCode != 200) {
|
||||
Log.d("GitLab getUserInfo: Invalid response " +
|
||||
Log.e("GitLab getUserInfo: Invalid response " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
return null;
|
||||
|
||||
var ex = GitHostException.HttpResponseFail;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
Map<String, dynamic>? map = jsonDecode(response.body);
|
||||
if (map == null || map.isEmpty) {
|
||||
Log.d("GitLab getUserInfo: jsonDecode Failed " +
|
||||
Log.e("GitLab getUserInfo: jsonDecode Failed " +
|
||||
response.statusCode.toString() +
|
||||
": " +
|
||||
response.body);
|
||||
return null;
|
||||
|
||||
var ex = GitHostException.JsonDecodingFail;
|
||||
return Result.fail(ex);
|
||||
}
|
||||
|
||||
return UserInfo(
|
||||
return Result(UserInfo(
|
||||
name: map['name'],
|
||||
email: map['email'],
|
||||
username: map['username'],
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ class OAuthAppState extends State<OAuthApp> {
|
||||
child: const Text("List Repos"),
|
||||
onPressed: () async {
|
||||
try {
|
||||
var repos = await githost!.listRepos();
|
||||
var repos = await githost!.listRepos().getOrThrow();
|
||||
for (var repo in repos) {
|
||||
print(repo);
|
||||
}
|
||||
|
@ -64,12 +64,12 @@ class GitHostSetupAutoConfigurePageState
|
||||
_message = tr('setup.autoconfigure.readUser');
|
||||
});
|
||||
|
||||
userInfo = await gitHost!.getUserInfo();
|
||||
var userInfo = await gitHost!.getUserInfo().getOrThrow();
|
||||
var settings = Provider.of<Settings>(context, listen: false);
|
||||
if (userInfo != null && userInfo.name.isNotEmpty) {
|
||||
if (userInfo.name.isNotEmpty) {
|
||||
settings.gitAuthor = userInfo.name;
|
||||
}
|
||||
if (userInfo != null && userInfo.email.isNotEmpty) {
|
||||
if (userInfo.email.isNotEmpty) {
|
||||
settings.gitAuthorEmail = userInfo.email;
|
||||
}
|
||||
settings.save();
|
||||
|
@ -80,7 +80,7 @@ class GitHostSetupRepoSelectorState extends State<GitHostSetupRepoSelector> {
|
||||
Log.d("Starting RepoSelector");
|
||||
|
||||
try {
|
||||
var allRepos = await widget.gitHost.listRepos();
|
||||
var allRepos = await widget.gitHost.listRepos().getOrThrow();
|
||||
allRepos.sort((GitHostRepo a, GitHostRepo b) {
|
||||
if (a.updatedAt != null && b.updatedAt != null) {
|
||||
return a.updatedAt!.compareTo(b.updatedAt!);
|
||||
@ -210,7 +210,8 @@ class GitHostSetupRepoSelectorState extends State<GitHostSetupRepoSelector> {
|
||||
|
||||
try {
|
||||
var repoName = _textController.text.trim();
|
||||
var repo = await widget.gitHost.createRepo(repoName);
|
||||
var repo =
|
||||
await widget.gitHost.createRepo(repoName).getOrThrow();
|
||||
widget.onDone(repo);
|
||||
return;
|
||||
} catch (e, stacktrace) {
|
||||
|
Reference in New Issue
Block a user