From e8e1c583b0a8b5b109b587f1fb6ea7e4ff140f57 Mon Sep 17 00:00:00 2001 From: Axel Ogereau-Peltier <49279289+axel-op@users.noreply.github.com> Date: Sun, 10 May 2020 03:59:41 +0200 Subject: [PATCH 1/3] [pulls_service] [create] : add expected status code + change preview header --- lib/src/common/pulls_service.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/src/common/pulls_service.dart b/lib/src/common/pulls_service.dart index ddc51b22..69f13adc 100644 --- a/lib/src/common/pulls_service.dart +++ b/lib/src/common/pulls_service.dart @@ -53,9 +53,8 @@ class PullRequestsService extends Service { '/repos/${slug.fullName}/pulls', convert: (i) => PullRequest.fromJson(i), body: GitHubJson.encode(request), - preview: request.draft - ? 'application/vnd.github.shadow-cat-preview+json' - : null, + preview: 'application/vnd.github.sailor-v-preview+json', + statusCode: StatusCodes.CREATED, ); } From 3557dad6591f9f5a81e3a9cbe5eec49b13d80b55 Mon Sep 17 00:00:00 2001 From: Axel Ogereau-Peltier <49279289+axel-op@users.noreply.github.com> Date: Sun, 31 May 2020 01:48:27 +0200 Subject: [PATCH 2/3] Require an expected status code for every request --- lib/src/common/activity_service.dart | 79 ++++++----- lib/src/common/gists_service.dart | 57 +++++--- lib/src/common/git_service.dart | 26 ++-- lib/src/common/github.dart | 10 +- lib/src/common/issues_service.dart | 155 ++++++++++++++-------- lib/src/common/misc_service.dart | 55 +++++--- lib/src/common/pulls_service.dart | 51 ++++--- lib/src/common/repos_service.dart | 93 ++++++++----- lib/src/common/url_shortener_service.dart | 2 +- lib/src/common/users_service.dart | 18 ++- 10 files changed, 349 insertions(+), 197 deletions(-) diff --git a/lib/src/common/activity_service.dart b/lib/src/common/activity_service.dart index 6fc03bb7..ec3c20a5 100644 --- a/lib/src/common/activity_service.dart +++ b/lib/src/common/activity_service.dart @@ -149,7 +149,7 @@ class ActivityService extends Service { /// Marks all notifications up to [lastRead] as read. /// - /// API docs: https://developer.github.com/v3/activity/notifications/#mark-as-read + /// API docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read Future markNotificationsRead({DateTime lastRead}) { final data = {}; @@ -158,7 +158,9 @@ class ActivityService extends Service { } return github - .request('PUT', '/notifications', body: GitHubJson.encode(data)) + .request('PUT', '/notifications', + body: GitHubJson.encode(data), + statusCode: StatusCodes.RESET_CONTENT) .then((response) { return response.statusCode == 205; }); @@ -180,7 +182,8 @@ class ActivityService extends Service { return github .request('PUT', '/repos/${slug.fullName}/notifications', - body: GitHubJson.encode(data)) + body: GitHubJson.encode(data), + statusCode: StatusCodes.RESET_CONTENT) .then((response) { return response.statusCode == 205; }); @@ -198,7 +201,8 @@ class ActivityService extends Service { /// API docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read Future markThreadRead(String threadId) { return github - .request('PATCH', '/notifications/threads/$threadId') + .request('PATCH', '/notifications/threads/$threadId', + statusCode: StatusCodes.RESET_CONTENT) .then((response) { return response.statusCode == StatusCodes.RESET_CONTENT; }); @@ -234,33 +238,42 @@ class ActivityService extends Service { /// Checks if the currently authenticated user has starred the specified repository. /// - /// API docs: https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository - Future isStarred(RepositorySlug slug) { - return github - .request('GET', '/user/starred/${slug.fullName}') - .then((response) { - return response.statusCode == 204; - }); + /// API docs: https://developer.github.com/v3/activity/starring/#check-if-a-repository-is-starred-by-the-authenticated-user + Future isStarred(RepositorySlug slug) async { + try { + await github.request( + 'GET', + '/user/starred/${slug.fullName}', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; + } on NotFound { + return false; + } } /// Stars the specified repository for the currently authenticated user. /// - /// API docs: https://developer.github.com/v3/activity/starring/#star-a-repository - Future star(RepositorySlug slug) { - return github.request('PUT', '/user/starred/${slug.fullName}', - headers: {'Content-Length': '0'}).then((response) { - return null; - }); + /// API docs: https://developer.github.com/v3/activity/starring/#star-a-repository-for-the-authenticated-user + Future star(RepositorySlug slug) async { + await github.request( + 'PUT', + '/user/starred/${slug.fullName}', + headers: {'Content-Length': '0'}, + statusCode: StatusCodes.NO_CONTENT, + ); } /// Unstars the specified repository for the currently authenticated user. /// - /// API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository - Future unstar(RepositorySlug slug) { - return github.request('DELETE', '/user/starred/${slug.fullName}', - headers: {'Content-Length': '0'}).then((response) { - return null; - }); + /// API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository-for-the-authenticated-user + Future unstar(RepositorySlug slug) async { + await github.request( + 'DELETE', + '/user/starred/${slug.fullName}', + headers: {'Content-Length': '0'}, + statusCode: StatusCodes.NO_CONTENT, + ); } /// Lists the watchers of the specified repository. @@ -318,11 +331,13 @@ class ActivityService extends Service { /// Deletes a Repository Subscription /// /// API docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription - Future deleteRepositorySubscription(RepositorySlug slug) { - return github.request('DELETE', '/repos/${slug.fullName}/subscription', - headers: {'Content-Length': '0'}).then((response) { - return null; - }); + Future deleteRepositorySubscription(RepositorySlug slug) async { + await github.request( + 'DELETE', + '/repos/${slug.fullName}/subscription', + headers: {'Content-Length': '0'}, + statusCode: StatusCodes.NO_CONTENT, + ); } } @@ -385,7 +400,9 @@ class EventPoller { headers['If-None-Match'] = _lastFetched; } - github.request('GET', path, headers: headers).then(handleEvent); + github + .request('GET', path, headers: headers, statusCode: null) + .then(handleEvent); }); } @@ -395,7 +412,9 @@ class EventPoller { headers['If-None-Match'] = _lastFetched; } - github.request('GET', path, headers: headers).then(handleEvent); + github + .request('GET', path, headers: headers, statusCode: null) + .then(handleEvent); return _controller.stream; } diff --git a/lib/src/common/gists_service.dart b/lib/src/common/gists_service.dart index 89b266bf..b40675d5 100644 --- a/lib/src/common/gists_service.dart +++ b/lib/src/common/gists_service.dart @@ -84,10 +84,13 @@ class GistsService extends Service { /// Deletes the specified Gist. /// /// API docs: https://developer.github.com/v3/gists/#delete-a-gist - Future deleteGist(String id) { - return github.request('DELETE', '/gists/$id').then((response) { - return response.statusCode == 204; - }); + Future deleteGist(String id) async { + await github.request( + 'DELETE', + '/gists/$id', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Edits a Gist. @@ -125,28 +128,41 @@ class GistsService extends Service { /// Star the specified Gist. /// /// API docs: https://developer.github.com/v3/gists/#star-a-gist - Future starGist(String id) { - return github.request('POST', '/gists/$id/star').then((response) { - return response.statusCode == 204; - }); + Future starGist(String id) async { + await github.request( + 'POST', + '/gists/$id/star', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Unstar the specified Gist. /// /// API docs: https://developer.github.com/v3/gists/#star-a-gist - Future unstarGist(String id) { - return github.request('DELETE', '/gists/$id/star').then((response) { - return response.statusCode == 204; - }); + Future unstarGist(String id) async { + await github.request( + 'DELETE', + '/gists/$id/star', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Checks if the specified Gist is starred. /// /// API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred - Future isGistStarred(String id) { - return github.request('GET', '/gists/$id/star').then((response) { - return response.statusCode == 204; - }); + Future isGistStarred(String id) async { + try { + await github.request( + 'GET', + '/gists/$id/star', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; + } on NotFound { + return false; + } } /// Forks the specified Gist. @@ -176,9 +192,12 @@ class GistsService extends Service { /// /// API docs: https://developer.github.com/v3/gists/comments/#create-a-comment Future createComment(String gistId, CreateGistComment request) { - return github.postJSON('/gists/$gistId/comments', - body: GitHubJson.encode(request), - convert: (i) => GistComment.fromJson(i)); + return github.postJSON( + '/gists/$gistId/comments', + body: GitHubJson.encode(request), + statusCode: StatusCodes.CREATED, + convert: (i) => GistComment.fromJson(i), + ); } // TODO: Implement editComment: https://developer.github.com/v3/gists/comments/#edit-a-comment diff --git a/lib/src/common/git_service.dart b/lib/src/common/git_service.dart index a6d9e98c..988bfcb1 100644 --- a/lib/src/common/git_service.dart +++ b/lib/src/common/git_service.dart @@ -98,21 +98,27 @@ class GitService extends Service { final headers = {'content-length': body.length.toString()}; return github - .request('PATCH', '/repos/${slug.fullName}/git/refs/$ref', - body: body, headers: headers) - .then((response) { - return GitReference.fromJson( - jsonDecode(response.body) as Map); - }); + .request( + 'PATCH', + '/repos/${slug.fullName}/git/refs/$ref', + body: body, + headers: headers, + statusCode: StatusCodes.OK, + ) + .then((response) => GitReference.fromJson( + jsonDecode(response.body) as Map)); } /// Deletes a reference. /// /// API docs: https://developer.github.com/v3/git/refs/#delete-a-reference - Future deleteReference(RepositorySlug slug, String ref) { - return github - .request('DELETE', '/repos/${slug.fullName}/git/refs/$ref') - .then((response) => response.statusCode == StatusCodes.NO_CONTENT); + Future deleteReference(RepositorySlug slug, String ref) async { + await github.request( + 'DELETE', + '/repos/${slug.fullName}/git/refs/$ref', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Fetches a tag from the repo given a SHA. diff --git a/lib/src/common/github.dart b/lib/src/common/github.dart index 27e36c5e..506f649d 100644 --- a/lib/src/common/github.dart +++ b/lib/src/common/github.dart @@ -143,7 +143,7 @@ class GitHub { /// The default [convert] function returns the input object. Future getJSON( String path, { - int statusCode, + @required int statusCode, void Function(http.Response response) fail, Map headers, Map params, @@ -183,7 +183,7 @@ class GitHub { /// [T] represents the type return from this function after conversion Future postJSON( String path, { - int statusCode, + @required int statusCode, void Function(http.Response response) fail, Map headers, Map params, @@ -225,7 +225,7 @@ class GitHub { /// [T] represents the type return from this function after conversion Future putJSON( String path, { - int statusCode, + @required int statusCode, void Function(http.Response response) fail, Map headers, Map params, @@ -248,7 +248,7 @@ class GitHub { Future requestJson( String method, String path, { - int statusCode, + @required int statusCode, void Function(http.Response response) fail, Map headers, Map params, @@ -298,10 +298,10 @@ class GitHub { Future request( String method, String path, { + @required int statusCode, Map headers, Map params, dynamic body, - int statusCode, void Function(http.Response response) fail, String preview, }) async { diff --git a/lib/src/common/issues_service.dart b/lib/src/common/issues_service.dart index db412d17..0f0d45ef 100644 --- a/lib/src/common/issues_service.dart +++ b/lib/src/common/issues_service.dart @@ -155,23 +155,28 @@ class IssuesService extends Service { /// Edit an issue. /// - /// API docs: https://developer.github.com/v3/issues/#edit-an-issue + /// API docs: https://developer.github.com/v3/issues/#update-an-issue Future edit( RepositorySlug slug, int issueNumber, IssueRequest issue) async { return github - .request('PATCH', '/repos/${slug.fullName}/issues/$issueNumber', - body: GitHubJson.encode(issue)) - .then((response) { - return Issue.fromJson(jsonDecode(response.body) as Map); - }); + .request( + 'PATCH', + '/repos/${slug.fullName}/issues/$issueNumber', + body: GitHubJson.encode(issue), + statusCode: StatusCodes.OK, + ) + .then((response) => + Issue.fromJson(jsonDecode(response.body) as Map)); } /// Get an issue. /// - /// API docs: https://developer.github.com/v3/issues/#get-a-single-issue - Future get(RepositorySlug slug, int issueNumber) => - github.getJSON('/repos/${slug.fullName}/issues/$issueNumber', - convert: (i) => Issue.fromJson(i)); + /// API docs: https://developer.github.com/v3/issues/#get-an-issue + Future get(RepositorySlug slug, int issueNumber) => github.getJSON( + '/repos/${slug.fullName}/issues/$issueNumber', + statusCode: StatusCodes.OK, + convert: (i) => Issue.fromJson(i), + ); /// Create an issue. /// @@ -180,6 +185,7 @@ class IssuesService extends Service { final response = await github.request( 'POST', '/repos/${slug.fullName}/issues', + statusCode: StatusCodes.CREATED, body: GitHubJson.encode(issue), ); @@ -203,10 +209,17 @@ class IssuesService extends Service { /// Checks if a user is an assignee for the specified repository. /// /// API docs: https://developer.github.com/v3/issues/assignees/#check-assignee - Future isAssignee(RepositorySlug slug, String repoName) { - return github - .request('GET', '/repos/${slug.fullName}/assignees/$repoName') - .then((response) => response.statusCode == StatusCodes.NO_CONTENT); + Future isAssignee(RepositorySlug slug, String repoName) async { + try { + await github.request( + 'GET', + '/repos/${slug.fullName}/assignees/$repoName', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; + } on NotFound { + return false; + } } /// Lists comments on the specified issue. @@ -234,8 +247,11 @@ class IssuesService extends Service { /// /// API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment Future getComment(RepositorySlug slug, int id) => - github.getJSON('/repos/${slug.fullName}/issues/comments/$id', - convert: (i) => IssueComment.fromJson(i)); + github.getJSON( + '/repos/${slug.fullName}/issues/comments/$id', + statusCode: StatusCodes.OK, + convert: (i) => IssueComment.fromJson(i), + ); /// Creates a new comment on the specified issue /// @@ -256,10 +272,13 @@ class IssuesService extends Service { /// Deletes an issue comment. /// /// API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment - Future deleteComment(RepositorySlug slug, int id) { - return github - .request('DELETE', '/repos/${slug.fullName}/issues/comments/$id') - .then((response) => response.statusCode == StatusCodes.NO_CONTENT); + Future deleteComment(RepositorySlug slug, int id) async { + await github.request( + 'DELETE', + '/repos/${slug.fullName}/issues/comments/$id', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } // TODO: Implement issues events methods: https://developer.github.com/v3/issues/events/ @@ -284,28 +303,36 @@ class IssuesService extends Service { /// API docs: https://developer.github.com/v3/issues/labels/#create-a-label Future createLabel( RepositorySlug slug, String name, String color) { - return github.postJSON('/repos/${slug.fullName}/labels', - body: GitHubJson.encode({'name': name, 'color': color}), - convert: (i) => IssueLabel.fromJson(i)); + return github.postJSON( + '/repos/${slug.fullName}/labels', + body: GitHubJson.encode({'name': name, 'color': color}), + statusCode: StatusCodes.CREATED, + convert: (i) => IssueLabel.fromJson(i), + ); } /// Edits a label. /// /// API docs: https://developer.github.com/v3/issues/labels/#update-a-label Future editLabel(RepositorySlug slug, String name, String color) { - return github.postJSON('/repos/${slug.fullName}/labels/$name', - body: GitHubJson.encode({'name': name, 'color': color}), - convert: (i) => IssueLabel.fromJson(i)); + return github.postJSON( + '/repos/${slug.fullName}/labels/$name', + body: GitHubJson.encode({'name': name, 'color': color}), + statusCode: StatusCodes.OK, + convert: (i) => IssueLabel.fromJson(i), + ); } /// Deletes a label. /// /// API docs: https://developer.github.com/v3/issues/labels/#delete-a-label Future deleteLabel(RepositorySlug slug, String name) async { - final response = - await github.request('DELETE', '/repos/${slug.fullName}/labels/$name'); - - return response.statusCode == StatusCodes.NO_CONTENT; + await github.request( + 'DELETE', + '/repos/${slug.fullName}/labels/$name', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Lists all labels for an issue. @@ -322,10 +349,14 @@ class IssuesService extends Service { /// /// API docs: https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue Future> addLabelsToIssue( - RepositorySlug slug, int issueNumber, List labels) { + RepositorySlug slug, + int issueNumber, + List labels, + ) { return github.postJSON, List>( '/repos/${slug.fullName}/issues/$issueNumber/labels', body: GitHubJson.encode(labels), + statusCode: StatusCodes.OK, convert: (input) => input .cast>() .map((i) => IssueLabel.fromJson(i)) @@ -339,12 +370,14 @@ class IssuesService extends Service { Future> replaceLabelsForIssue( RepositorySlug slug, int issueNumber, List labels) { return github - .request('PUT', '/repos/${slug.fullName}/issues/$issueNumber/labels', - body: GitHubJson.encode(labels)) - .then((response) { - return jsonDecode(response.body) - .map((Map it) => IssueLabel.fromJson(it)); - }); + .request( + 'PUT', + '/repos/${slug.fullName}/issues/$issueNumber/labels', + body: GitHubJson.encode(labels), + statusCode: StatusCodes.OK, + ) + .then((response) => jsonDecode(response.body) + .map((Map it) => IssueLabel.fromJson(it))); } /// Removes a label for an issue. @@ -352,19 +385,27 @@ class IssuesService extends Service { /// API docs: https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue Future removeLabelForIssue( RepositorySlug slug, int issueNumber, String label) async { - final response = await github.request( - 'DELETE', '/repos/${slug.fullName}/issues/$issueNumber/labels/$label'); - - return response.statusCode == StatusCodes.OK; + await github.request( + 'DELETE', + '/repos/${slug.fullName}/issues/$issueNumber/labels/$label', + statusCode: StatusCodes.OK, + ); + return true; } /// Removes all labels for an issue. /// /// API docs: https://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue - Future removeAllLabelsForIssue(RepositorySlug slug, int issueNumber) { - return github - .request('DELETE', '/repos/${slug.fullName}/issues/$issueNumber/labels') - .then((response) => response.statusCode == StatusCodes.NO_CONTENT); + Future removeAllLabelsForIssue( + RepositorySlug slug, + int issueNumber, + ) async { + await github.request( + 'DELETE', + '/repos/${slug.fullName}/issues/$issueNumber/labels', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } // TODO: Implement listLabelsByMilestone: https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone @@ -383,10 +424,15 @@ class IssuesService extends Service { /// /// API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone Future createMilestone( - RepositorySlug slug, CreateMilestone request) { - return github.postJSON('/repos/${slug.fullName}/milestones', - body: GitHubJson.encode(request), - convert: (i) => Milestone.fromJson(i)); + RepositorySlug slug, + CreateMilestone request, + ) { + return github.postJSON( + '/repos/${slug.fullName}/milestones', + statusCode: StatusCodes.CREATED, + body: GitHubJson.encode(request), + convert: (i) => Milestone.fromJson(i), + ); } // TODO: Implement editMilestone: https://developer.github.com/v3/issues/milestones/#update-a-milestone @@ -394,9 +440,12 @@ class IssuesService extends Service { /// Deletes a milestone. /// /// API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone - Future deleteMilestone(RepositorySlug slug, int number) { - return github - .request('DELETE', '/repos/${slug.fullName}/milestones/$number') - .then((response) => response.statusCode == StatusCodes.NO_CONTENT); + Future deleteMilestone(RepositorySlug slug, int number) async { + await github.request( + 'DELETE', + '/repos/${slug.fullName}/milestones/$number', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } } diff --git a/lib/src/common/misc_service.dart b/lib/src/common/misc_service.dart index 9ccc289b..cd9e873c 100644 --- a/lib/src/common/misc_service.dart +++ b/lib/src/common/misc_service.dart @@ -25,16 +25,21 @@ class MiscService extends Service { /// /// API docs: https://developer.github.com/v3/gitignore/#listing-available-templates Future> listGitignoreTemplates() { - return github.getJSON('/gitignore/templates') as Future>; + return github.getJSON( + '/gitignore/templates', + statusCode: StatusCodes.OK, + ) as Future>; } /// Gets a .gitignore template by [name]. /// All template names can be fetched using [listGitignoreTemplates]. /// /// API docs: https://developer.github.com/v3/gitignore/#get-a-single-template - Future getGitignoreTemplate(String name) => - github.getJSON('/gitignore/templates/$name', - convert: (i) => GitignoreTemplate.fromJson(i)); + Future getGitignoreTemplate(String name) => github.getJSON( + '/gitignore/templates/$name', + convert: (i) => GitignoreTemplate.fromJson(i), + statusCode: StatusCodes.OK, + ); /// Renders Markdown from the [input]. /// @@ -42,15 +47,22 @@ class MiscService extends Service { /// [context] is the repository context. Only take into account when [mode] is 'gfm'. /// /// API docs: https://developer.github.com/v3/markdown/#render-an-arbitrary-markdown-document - Future renderMarkdown(String input, - {String mode = 'markdown', String context}) { - return github - .request('POST', '/markdown', - body: GitHubJson.encode( - {'text': input, 'mode': mode, 'context': context})) - .then((response) { - return response.body; - }); + Future renderMarkdown( + String input, { + String mode = 'markdown', + String context, + }) async { + final response = await github.request( + 'POST', + '/markdown', + body: GitHubJson.encode({ + 'text': input, + 'mode': mode, + 'context': context, + }), + statusCode: StatusCodes.OK, + ); + return response.body; } // TODO: Implement renderMarkdownRaw: https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode @@ -61,9 +73,9 @@ class MiscService extends Service { /// /// API docs: https://developer.github.com/v3/rate_limit/ Future getRateLimit() { - return github.request('GET', '/').then((response) { - return RateLimit.fromHeaders(response.headers); - }); + return github + .request('GET', '/', statusCode: StatusCodes.OK) + .then((response) => RateLimit.fromHeaders(response.headers)); } /// Gets the GitHub API Status. @@ -79,16 +91,17 @@ class MiscService extends Service { params['s'] = text; } - return github.request('GET', '/octocat', params: params).then((response) { - return response.body; - }); + return github + .request('GET', '/octocat', params: params, statusCode: StatusCodes.OK) + .then((response) => response.body); } /// Returns an ASCII Octocat with some wisdom. Future getWisdom() => getOctocat(); - Future getZen() => - github.request('GET', '/zen').then((response) => response.body); + Future getZen() => github + .request('GET', '/zen', statusCode: StatusCodes.OK) + .then((response) => response.body); } class Octocat { diff --git a/lib/src/common/pulls_service.dart b/lib/src/common/pulls_service.dart index 69f13adc..58104b03 100644 --- a/lib/src/common/pulls_service.dart +++ b/lib/src/common/pulls_service.dart @@ -61,8 +61,14 @@ class PullRequestsService extends Service { /// Edit a pull request. /// /// API docs: https://developer.github.com/v3/pulls/#update-a-pull-request - Future edit(RepositorySlug slug, int number, - {String title, String body, String state, String base}) { + Future edit( + RepositorySlug slug, + int number, { + String title, + String body, + String state, + String base, + }) { final map = {}; putValue('title', title, map); putValue('body', body, map); @@ -70,12 +76,14 @@ class PullRequestsService extends Service { putValue('base', base, map); return github - .request('POST', '/repos/${slug.fullName}/pulls/$number', - body: GitHubJson.encode(map)) - .then((response) { - return PullRequest.fromJson( - jsonDecode(response.body) as Map); - }); + .request( + 'PATCH', + '/repos/${slug.fullName}/pulls/$number', + body: GitHubJson.encode(map), + statusCode: StatusCodes.OK, + ) + .then((response) => PullRequest.fromJson( + jsonDecode(response.body) as Map)); } /// Lists the commits in a pull request. @@ -98,12 +106,13 @@ class PullRequestsService extends Service { (i) => PullRequestFile.fromJson(i)); } - Future isMerged(RepositorySlug slug, int number) { - return github - .request('GET', '/repos/${slug.fullName}/pulls/$number/merge') - .then((response) { - return response.statusCode == 204; - }); + Future isMerged(RepositorySlug slug, int number) async { + await github.request( + 'GET', + '/repos/${slug.fullName}/pulls/$number/merge', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Merge a pull request (Merge Button). @@ -121,12 +130,14 @@ class PullRequestsService extends Service { } return github - .request('PUT', '/repos/${slug.fullName}/pulls/$number/merge', - body: GitHubJson.encode(json)) - .then((response) { - return PullRequestMerge.fromJson( - jsonDecode(response.body) as Map); - }); + .request( + 'PUT', + '/repos/${slug.fullName}/pulls/$number/merge', + body: GitHubJson.encode(json), + statusCode: StatusCodes.OK, + ) + .then((response) => PullRequestMerge.fromJson( + jsonDecode(response.body) as Map)); } /// Lists all comments on the specified pull request. diff --git a/lib/src/common/repos_service.dart b/lib/src/common/repos_service.dart index bb477027..f8771d16 100644 --- a/lib/src/common/repos_service.dart +++ b/lib/src/common/repos_service.dart @@ -103,23 +103,22 @@ class RepositoriesService extends Service { /// repository will be created under that organization. If no [org] is /// specified, it will be created for the authenticated user. /// - /// API docs: https://developer.github.com/v3/repos/#create - Future createRepository(CreateRepository repository, - {String org}) async { + /// * API docs: https://developer.github.com/v3/repos/#create-a-repository-for-the-authenticated-user + /// * API docs: + Future createRepository( + CreateRepository repository, { + String org, + }) async { ArgumentError.checkNotNull(repository); - if (org != null) { - return github.postJSON, TeamRepository>( - '/orgs/$org/repos', - body: GitHubJson.encode(repository), - convert: (i) => TeamRepository.fromJson(i), - ); - } else { - return github.postJSON, Repository>( - '/user/repos', - body: GitHubJson.encode(repository), - convert: (i) => Repository.fromJson(i), - ); - } + final isOrg = org != null; + final path = isOrg ? '/orgs/$org/repos' : '/user/repos'; + return github.postJSON, Repository>( + path, + body: GitHubJson.encode(repository), + convert: (i) => + isOrg ? TeamRepository.fromJson(i) : Repository.fromJson(i), + statusCode: StatusCodes.CREATED, + ); } Future getLicense(RepositorySlug slug) async { @@ -127,6 +126,7 @@ class RepositoriesService extends Service { return github.getJSON, LicenseDetails>( '/repos/${slug.owner}/${slug.name}/license', convert: (json) => LicenseDetails.fromJson(json), + statusCode: StatusCodes.OK, ); } @@ -272,6 +272,7 @@ class RepositoriesService extends Service { return github.getJSON, Branch>( '/repos/${slug.fullName}/branches/$branch', convert: (i) => Branch.fromJson(i), + statusCode: StatusCodes.OK, ); } @@ -507,6 +508,7 @@ class RepositoriesService extends Service { return github.getJSON, GitHubComparison>( '/repos/${slug.fullName}/compare/$refBase...$refHead', convert: (j) => GitHubComparison.fromJson(j), + statusCode: StatusCodes.OK, ); } @@ -567,6 +569,7 @@ class RepositoriesService extends Service { return github.getJSON( url, + statusCode: StatusCodes.OK, convert: (input) { final contents = RepositoryContents(); if (input is Map) { @@ -589,15 +592,18 @@ class RepositoriesService extends Service { /// Creates a new file in a repository. /// - /// API docs: https://developer.github.com/v3/repos/contents/#create-a-file + /// API docs: https://developer.github.com/v3/repos/contents/#create-or-update-a-file Future createFile( - RepositorySlug slug, CreateFile file) async { + RepositorySlug slug, + CreateFile file, + ) async { ArgumentError.checkNotNull(slug); ArgumentError.checkNotNull(file); final response = await github.request( 'PUT', '/repos/${slug.fullName}/contents/${file.path}', body: GitHubJson.encode(file), + statusCode: StatusCodes.CREATED, ); return ContentCreation.fromJson( jsonDecode(response.body) as Map); @@ -605,10 +611,15 @@ class RepositoriesService extends Service { /// Updates the specified file. /// - /// API docs: https://developer.github.com/v3/repos/contents/#update-a-file - Future updateFile(RepositorySlug slug, String path, - String message, String content, String sha, - {String branch}) async { + /// API docs: https://developer.github.com/v3/repos/contents/#create-or-update-a-file + Future updateFile( + RepositorySlug slug, + String path, + String message, + String content, + String sha, { + String branch, + }) async { ArgumentError.checkNotNull(slug); ArgumentError.checkNotNull(path); final map = createNonNullMap({ @@ -621,6 +632,7 @@ class RepositoriesService extends Service { 'PUT', '/repos/${slug.fullName}/contents/$path', body: GitHubJson.encode(map), + statusCode: StatusCodes.CREATED, ); return ContentCreation.fromJson( jsonDecode(response.body) as Map); @@ -683,6 +695,7 @@ class RepositoriesService extends Service { '/repos/${slug.fullName}/forks', body: GitHubJson.encode(fork), convert: (i) => Repository.fromJson(i), + statusCode: StatusCodes.ACCEPTED, ); } @@ -707,6 +720,7 @@ class RepositoriesService extends Service { return github.getJSON, Hook>( '/repos/${slug.fullName}/hooks/$id', convert: (i) => Hook.fromJson(i)..repoName = slug.fullName, + statusCode: StatusCodes.OK, ); } @@ -720,6 +734,7 @@ class RepositoriesService extends Service { '/repos/${slug.fullName}/hooks', convert: (i) => Hook.fromJson(i)..repoName = slug.fullName, body: GitHubJson.encode(hook), + statusCode: StatusCodes.CREATED, ); } @@ -951,6 +966,7 @@ class RepositoriesService extends Service { return github.getJSON, Release>( '/repos/${slug.fullName}/releases/$id', convert: (i) => Release.fromJson(i), + statusCode: StatusCodes.OK, ); } @@ -958,8 +974,11 @@ class RepositoriesService extends Service { /// /// API docs: https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name Future getReleaseByTagName(RepositorySlug slug, String tagName) => - github.getJSON('/repos/${slug.fullName}/releases/tags/$tagName', - convert: (i) => Release.fromJson(i)); + github.getJSON( + '/repos/${slug.fullName}/releases/tags/$tagName', + convert: (i) => Release.fromJson(i), + statusCode: StatusCodes.OK, + ); /// Creates a Release based on the specified [createRelease]. /// @@ -977,6 +996,7 @@ class RepositoriesService extends Service { '/repos/${slug.fullName}/releases', convert: (i) => Release.fromJson(i), body: GitHubJson.encode(createRelease.toJson()), + statusCode: StatusCodes.CREATED, ); if (release.hasErrors) { final alreadyExistsErrorCode = release.errors.firstWhere( @@ -1124,13 +1144,15 @@ class RepositoriesService extends Service { for (final createReleaseAsset in createReleaseAssets) { final headers = {'Content-Type': createReleaseAsset.contentType}; final releaseAsset = await github.postJSON( - release.getUploadUrlFor( - createReleaseAsset.name, - createReleaseAsset.label, - ), - headers: headers, - body: createReleaseAsset.assetData, - convert: (i) => ReleaseAsset.fromJson(i)); + release.getUploadUrlFor( + createReleaseAsset.name, + createReleaseAsset.label, + ), + headers: headers, + body: createReleaseAsset.assetData, + convert: (i) => ReleaseAsset.fromJson(i), + statusCode: StatusCodes.CREATED, + ); releaseAssets.add(releaseAsset); } return releaseAssets; @@ -1147,8 +1169,12 @@ class RepositoriesService extends Service { ) async { ArgumentError.checkNotNull(slug); final path = '/repos/${slug.fullName}/stats/contributors'; - final response = - await github.request('GET', path, headers: {'Accept': v3ApiMimeType}); + final response = await github.request( + 'GET', + path, + headers: {'Accept': v3ApiMimeType}, + statusCode: StatusCodes.OK, + ); if (response.statusCode == StatusCodes.OK) { return (jsonDecode(response.body) as List) @@ -1239,6 +1265,7 @@ class RepositoriesService extends Service { '/repos/${slug.fullName}/statuses/$ref', body: GitHubJson.encode(request), convert: (i) => RepositoryStatus.fromJson(i), + statusCode: StatusCodes.OK, ); } diff --git a/lib/src/common/url_shortener_service.dart b/lib/src/common/url_shortener_service.dart index 950b0844..8309cd5d 100644 --- a/lib/src/common/url_shortener_service.dart +++ b/lib/src/common/url_shortener_service.dart @@ -20,7 +20,7 @@ class UrlShortenerService extends Service { } return github - .request('POST', 'http://git.io/', params: params) + .request('POST', 'http://git.io/', params: params, statusCode: null) .then((response) { if (response.statusCode != StatusCodes.CREATED) { throw GitHubError(github, 'Failed to create shortened url!'); diff --git a/lib/src/common/users_service.dart b/lib/src/common/users_service.dart index ad59d9ea..c8ebcaff 100644 --- a/lib/src/common/users_service.dart +++ b/lib/src/common/users_service.dart @@ -15,8 +15,11 @@ class UsersService extends Service { /// Fetches the user specified by [name]. /// /// API docs: https://developer.github.com/v3/users/#get-a-single-user - Future getUser(String name) => - github.getJSON('/users/$name', convert: (i) => User.fromJson(i)); + Future getUser(String name) => github.getJSON( + '/users/$name', + convert: (i) => User.fromJson(i), + statusCode: StatusCodes.OK, + ); /// Updates the Current User. /// @@ -70,9 +73,14 @@ class UsersService extends Service { convert: (i) => CurrentUser.fromJson(i)); /// Checks if a user exists. - Future isUser(String name) => github - .request('GET', '/users/$name') - .then((resp) => resp.statusCode == StatusCodes.OK); + Future isUser(String name) async { + try { + await github.request('GET', '/users/$name', statusCode: StatusCodes.OK); + return true; + } on NotFound { + return false; + } + } // TODO: Implement editUser: https://developer.github.com/v3/users/#update-the-authenticated-user From 6a02421f4fb002bed7367df78bae07de64a9cd47 Mon Sep 17 00:00:00 2001 From: Axel Ogereau-Peltier <49279289+axel-op@users.noreply.github.com> Date: Sun, 31 May 2020 01:48:45 +0200 Subject: [PATCH 3/3] Deprecate methods in orgs_service --- lib/src/common/orgs_service.dart | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/src/common/orgs_service.dart b/lib/src/common/orgs_service.dart index 3f3dfa6c..53863b15 100644 --- a/lib/src/common/orgs_service.dart +++ b/lib/src/common/orgs_service.dart @@ -125,23 +125,28 @@ class OrganizationsService extends Service { ); } - /// Deletes the team specified by the [teamId] + /// Deletes the team specified by the [teamSlug] /// /// API docs: https://developer.github.com/v3/orgs/teams/#delete-team - Future deleteTeam(int teamId) { - return github.request('DELETE', '/teams/$teamId').then((response) { - return response.statusCode == 204; - }); + Future deleteTeam(String org, String teamSlug) async { + await github.request( + 'DELETE', + 'orgs/$org/teams/$teamSlug', + statusCode: StatusCodes.NO_CONTENT, + ); + return true; } /// Lists the team members of the team with [teamId]. /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-team-members + @deprecated Stream listTeamMembers(int teamId) { return PaginationHelper(github).objects( 'GET', '/teams/$teamId/members', (i) => TeamMember.fromJson(i)); } + @deprecated Future getTeamMemberStatus(int teamId, String user) { return github.getJSON('/teams/$teamId/memberships/$user').then((json) { return json['state']; @@ -151,6 +156,7 @@ class OrganizationsService extends Service { /// Returns the membership status for a user in a team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership + @deprecated Future getTeamMembership(int teamId, String user) { final completer = Completer(); @@ -175,6 +181,7 @@ class OrganizationsService extends Service { /// Invites a user to the specified team. /// /// API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership + @deprecated Future addTeamMembership(int teamId, String user) async { final response = await github .request('PUT', '/teams/$teamId/memberships/$user', statusCode: 200); @@ -184,6 +191,7 @@ class OrganizationsService extends Service { /// Removes a user from the specified team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership + @deprecated Future removeTeamMembership(int teamId, String user) { return github.request('DELETE', '/teams/$teamId/memberships/$user', statusCode: 204); @@ -192,6 +200,7 @@ class OrganizationsService extends Service { /// Lists the repositories that the specified team has access to. /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-team-repos + @deprecated Stream listTeamRepositories(int teamId) { return PaginationHelper(github) .objects('GET', '/teams/$teamId/repos', (i) => Repository.fromJson(i)); @@ -200,6 +209,7 @@ class OrganizationsService extends Service { /// Checks if a team manages the specified repository. /// /// API docs: https://developer.github.com/v3/orgs/teams/#get-team-repo + @deprecated Future isTeamRepository(int teamId, RepositorySlug slug) { return github .request('GET', '/teams/$teamId/repos/${slug.fullName}') @@ -211,6 +221,7 @@ class OrganizationsService extends Service { /// Adds a repository to be managed by the specified team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#add-team-repo + @deprecated Future addTeamRepository(int teamId, RepositorySlug slug) { return github .request('PUT', '/teams/$teamId/repos/${slug.fullName}') @@ -222,6 +233,7 @@ class OrganizationsService extends Service { /// Removes a repository from being managed by the specified team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#remove-team-repo + @deprecated Future removeTeamRepository(int teamId, RepositorySlug slug) { return github .request('DELETE', '/teams/$teamId/repos/${slug.fullName}')