From 3e52a6a2483189de7c1055678f33d01e6a28ca9c Mon Sep 17 00:00:00 2001 From: Joshua Potts <8704475+iamjpotts@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:34:37 -0500 Subject: [PATCH] Add Octocrab::users() and UsersHandler::repos --- CHANGELOG.md | 1 + README.md | 2 + src/api.rs | 1 + src/api/users.rs | 24 +++ src/api/users/user_repos.rs | 101 ++++++++++++ src/lib.rs | 10 ++ src/params.rs | 18 ++ tests/resources/user_repositories.json | 218 +++++++++++++++++++++++++ tests/user_repositories_tests.rs | 105 ++++++++++++ 9 files changed, 480 insertions(+) create mode 100644 src/api/users.rs create mode 100644 src/api/users/user_repos.rs create mode 100644 tests/resources/user_repositories.json create mode 100644 tests/user_repositories_tests.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index e1b5bc7d..5dd11be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- add Octocrab::users and UsersHandler::repos ## [0.29.3](https://github.com/XAMPPRocky/octocrab/compare/v0.29.2...v0.29.3) - 2023-08-15 diff --git a/README.md b/README.md index de53e1c6..88d6e687 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Currently, the following modules are available as of version `0.17`. - [`search`] GitHub's search API. - [`teams`] Teams. - [`gists`] GitHub's gists API +- [`users`] Users. [`models`]: https://docs.rs/octocrab/latest/octocrab/models/index.html [`auth`]: https://docs.rs/octocrab/latest/octocrab/auth/index.html @@ -58,6 +59,7 @@ Currently, the following modules are available as of version `0.17`. [`search`]: https://docs.rs/octocrab/latest/octocrab/search/struct.SearchHandler.html [`teams`]: https://docs.rs/octocrab/latest/octocrab/teams/struct.TeamHandler.html [`gists`]: https://docs.rs/octocrab/latest/octocrab/gists/struct.GistsHandler.html +[`users`]: https://docs.rs/octocrab/latest/octocrab/gists/struct.UsersHandler.html #### Getting a Pull Request ```rust diff --git a/src/api.rs b/src/api.rs index 5675ccdc..7c21b00f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -17,4 +17,5 @@ pub mod ratelimit; pub mod repos; pub mod search; pub mod teams; +pub mod users; pub mod workflows; diff --git a/src/api/users.rs b/src/api/users.rs new file mode 100644 index 00000000..a9cf5c1d --- /dev/null +++ b/src/api/users.rs @@ -0,0 +1,24 @@ +//! The users API. + +mod user_repos; + +pub use self::user_repos::ListUserReposBuilder; +use crate::Octocrab; + +pub struct UserHandler<'octo> { + crab: &'octo Octocrab, + user: String +} + +impl<'octo> UserHandler<'octo> { + pub(crate) fn new(crab: &'octo Octocrab, user: String) -> Self { + Self { crab, user } + } + + pub fn repos( + &self + ) -> ListUserReposBuilder<'_, '_> { + ListUserReposBuilder::new(self) + } + +} diff --git a/src/api/users/user_repos.rs b/src/api/users/user_repos.rs new file mode 100644 index 00000000..10411ef4 --- /dev/null +++ b/src/api/users/user_repos.rs @@ -0,0 +1,101 @@ +use crate::api::users::UserHandler; +use crate::Page; + +/// A builder pattern struct for listing a user's repositories. +/// +/// created by [`UserHandler::repos`] +/// +/// [`UserHandler::repos`]: ./struct.UserHandler.html#method.repos +#[derive(serde::Serialize)] +pub struct ListUserReposBuilder<'octo, 'b> { + #[serde(skip)] + handler: &'b UserHandler<'octo>, + #[serde(skip_serializing_if = "Option::is_none")] + r#type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + sort: Option, + #[serde(skip_serializing_if = "Option::is_none")] + direction: Option, + #[serde(skip_serializing_if = "Option::is_none")] + per_page: Option, + #[serde(skip_serializing_if = "Option::is_none")] + page: Option, +} + +impl<'octo, 'b> ListUserReposBuilder<'octo, 'b> { + pub(crate) fn new(handler: &'b UserHandler<'octo>) -> Self { + Self { + handler, + r#type: None, + sort: None, + direction: None, + per_page: None, + page: None, + } + } + + /// Repository ownership type. + pub fn r#type(mut self, r#type: impl Into) -> Self { + self.r#type = Some(r#type.into()); + self + } + + /// What to sort results by. + pub fn sort(mut self, sort: impl Into) -> Self { + self.sort = Some(sort.into()); + self + } + + /// The direction of the sort. + pub fn direction(mut self, direction: impl Into) -> Self { + self.direction = Some(direction.into()); + self + } + + /// Results per page (max 100). + pub fn per_page(mut self, per_page: impl Into) -> Self { + self.per_page = Some(per_page.into()); + self + } + + /// Page number of the results to fetch. + pub fn page(mut self, page: impl Into) -> Self { + self.page = Some(page.into()); + self + } + + /// Sends the actual request. + pub async fn send(self) -> crate::Result> { + let route = format!( + "/users/{user}/repos", + user = self.handler.user + ); + self.handler.crab.get(route, Some(&self)).await + } +} + +#[cfg(test)] +mod tests { + #[tokio::test] + async fn serialize() { + let octocrab = crate::Octocrab::default(); + let handler = octocrab.users("foo"); + let request = handler.repos() + .r#type(crate::params::users::repos::Type::Member) + .sort(crate::params::repos::Sort::Updated) + .direction(crate::params::Direction::Ascending) + .per_page(87) + .page(3u8); + + assert_eq!( + serde_json::to_value(request).unwrap(), + serde_json::json!({ + "type": "member", + "sort": "updated", + "direction": "asc", + "per_page": 87, + "page": 3, + }) + ) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7c61641c..1c851037 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ //! - [`repos::releases`] Repositories //! - [`search`] Using GitHub's search. //! - [`teams`] Teams +//! - [`users`] Users //! //! #### Getting a Pull Request //! ```no_run @@ -248,6 +249,7 @@ use crate::service::middleware::retry::RetryConfig; use auth::{AppAuth, Auth}; use models::{AppId, InstallationId, InstallationToken}; +use crate::api::users; pub use self::{ api::{ @@ -1065,6 +1067,14 @@ impl Octocrab { teams::TeamHandler::new(self, owner.into()) } + /// Creates a [`users::UserHandler`] for the specified user + pub fn users( + &self, + user: impl Into + ) -> users::UserHandler { + users::UserHandler::new(self, user.into()) + } + /// Creates a [`workflows::WorkflowsHandler`] for the specified repository that allows /// you to access GitHub's workflows API. pub fn workflows( diff --git a/src/params.rs b/src/params.rs index e5648cd1..dc35a717 100644 --- a/src/params.rs +++ b/src/params.rs @@ -391,3 +391,21 @@ pub mod workflows { All, } } + +pub mod users { + //! Parameter types for the users API. + + pub mod repos { + /// What ownership type to filter a user repository list by. + /// + /// See https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-a-user + #[derive(Debug, Clone, Copy, serde::Serialize)] + #[serde(rename_all = "snake_case")] + #[non_exhaustive] + pub enum Type { + All, + Owner, + Member, + } + } +} \ No newline at end of file diff --git a/tests/resources/user_repositories.json b/tests/resources/user_repositories.json new file mode 100644 index 00000000..640fe4fa --- /dev/null +++ b/tests/resources/user_repositories.json @@ -0,0 +1,218 @@ +[ + { + "id": 566109822, + "node_id": "R_kgDOIb4mfg", + "name": "actix-examples", + "full_name": "iamjpotts/actix-examples", + "private": false, + "owner": { + "login": "iamjpotts", + "id": 8704475, + "node_id": "MDQ6VXNlcjg3MDQ0NzU=", + "avatar_url": "https://avatars.githubusercontent.com/u/8704475?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/iamjpotts", + "html_url": "https://github.com/iamjpotts", + "followers_url": "https://api.github.com/users/iamjpotts/followers", + "following_url": "https://api.github.com/users/iamjpotts/following{/other_user}", + "gists_url": "https://api.github.com/users/iamjpotts/gists{/gist_id}", + "starred_url": "https://api.github.com/users/iamjpotts/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/iamjpotts/subscriptions", + "organizations_url": "https://api.github.com/users/iamjpotts/orgs", + "repos_url": "https://api.github.com/users/iamjpotts/repos", + "events_url": "https://api.github.com/users/iamjpotts/events{/privacy}", + "received_events_url": "https://api.github.com/users/iamjpotts/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/iamjpotts/actix-examples", + "description": "Community showcase and examples of Actix ecosystem usage.", + "fork": true, + "url": "https://api.github.com/repos/iamjpotts/actix-examples", + "forks_url": "https://api.github.com/repos/iamjpotts/actix-examples/forks", + "keys_url": "https://api.github.com/repos/iamjpotts/actix-examples/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/iamjpotts/actix-examples/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/iamjpotts/actix-examples/teams", + "hooks_url": "https://api.github.com/repos/iamjpotts/actix-examples/hooks", + "issue_events_url": "https://api.github.com/repos/iamjpotts/actix-examples/issues/events{/number}", + "events_url": "https://api.github.com/repos/iamjpotts/actix-examples/events", + "assignees_url": "https://api.github.com/repos/iamjpotts/actix-examples/assignees{/user}", + "branches_url": "https://api.github.com/repos/iamjpotts/actix-examples/branches{/branch}", + "tags_url": "https://api.github.com/repos/iamjpotts/actix-examples/tags", + "blobs_url": "https://api.github.com/repos/iamjpotts/actix-examples/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/iamjpotts/actix-examples/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/iamjpotts/actix-examples/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/iamjpotts/actix-examples/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/iamjpotts/actix-examples/statuses/{sha}", + "languages_url": "https://api.github.com/repos/iamjpotts/actix-examples/languages", + "stargazers_url": "https://api.github.com/repos/iamjpotts/actix-examples/stargazers", + "contributors_url": "https://api.github.com/repos/iamjpotts/actix-examples/contributors", + "subscribers_url": "https://api.github.com/repos/iamjpotts/actix-examples/subscribers", + "subscription_url": "https://api.github.com/repos/iamjpotts/actix-examples/subscription", + "commits_url": "https://api.github.com/repos/iamjpotts/actix-examples/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/iamjpotts/actix-examples/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/iamjpotts/actix-examples/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/iamjpotts/actix-examples/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/iamjpotts/actix-examples/contents/{+path}", + "compare_url": "https://api.github.com/repos/iamjpotts/actix-examples/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/iamjpotts/actix-examples/merges", + "archive_url": "https://api.github.com/repos/iamjpotts/actix-examples/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/iamjpotts/actix-examples/downloads", + "issues_url": "https://api.github.com/repos/iamjpotts/actix-examples/issues{/number}", + "pulls_url": "https://api.github.com/repos/iamjpotts/actix-examples/pulls{/number}", + "milestones_url": "https://api.github.com/repos/iamjpotts/actix-examples/milestones{/number}", + "notifications_url": "https://api.github.com/repos/iamjpotts/actix-examples/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/iamjpotts/actix-examples/labels{/name}", + "releases_url": "https://api.github.com/repos/iamjpotts/actix-examples/releases{/id}", + "deployments_url": "https://api.github.com/repos/iamjpotts/actix-examples/deployments", + "created_at": "2022-11-15T01:30:03Z", + "updated_at": "2022-11-14T09:34:10Z", + "pushed_at": "2022-11-15T07:52:50Z", + "git_url": "git://github.com/iamjpotts/actix-examples.git", + "ssh_url": "git@github.com:iamjpotts/actix-examples.git", + "clone_url": "https://github.com/iamjpotts/actix-examples.git", + "svn_url": "https://github.com/iamjpotts/actix-examples", + "homepage": "", + "size": 2885, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": false, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master" + }, + { + "id": 292435601, + "node_id": "MDEwOlJlcG9zaXRvcnkyOTI0MzU2MDE=", + "name": "amazon-sqs-java-temporary-queues-client", + "full_name": "iamjpotts/amazon-sqs-java-temporary-queues-client", + "private": false, + "owner": { + "login": "iamjpotts", + "id": 8704475, + "node_id": "MDQ6VXNlcjg3MDQ0NzU=", + "avatar_url": "https://avatars.githubusercontent.com/u/8704475?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/iamjpotts", + "html_url": "https://github.com/iamjpotts", + "followers_url": "https://api.github.com/users/iamjpotts/followers", + "following_url": "https://api.github.com/users/iamjpotts/following{/other_user}", + "gists_url": "https://api.github.com/users/iamjpotts/gists{/gist_id}", + "starred_url": "https://api.github.com/users/iamjpotts/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/iamjpotts/subscriptions", + "organizations_url": "https://api.github.com/users/iamjpotts/orgs", + "repos_url": "https://api.github.com/users/iamjpotts/repos", + "events_url": "https://api.github.com/users/iamjpotts/events{/privacy}", + "received_events_url": "https://api.github.com/users/iamjpotts/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/iamjpotts/amazon-sqs-java-temporary-queues-client", + "description": "An Amazon SQS client that supports creating lightweight, automatically-deleted temporary queues, for use in common messaging patterns such as Request/Response. See http://aws.amazon.com/sqs.", + "fork": true, + "url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client", + "forks_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/forks", + "keys_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/teams", + "hooks_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/hooks", + "issue_events_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/issues/events{/number}", + "events_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/events", + "assignees_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/assignees{/user}", + "branches_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/branches{/branch}", + "tags_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/tags", + "blobs_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/statuses/{sha}", + "languages_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/languages", + "stargazers_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/stargazers", + "contributors_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/contributors", + "subscribers_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/subscribers", + "subscription_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/subscription", + "commits_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/contents/{+path}", + "compare_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/merges", + "archive_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/downloads", + "issues_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/issues{/number}", + "pulls_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/pulls{/number}", + "milestones_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/milestones{/number}", + "notifications_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/labels{/name}", + "releases_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/releases{/id}", + "deployments_url": "https://api.github.com/repos/iamjpotts/amazon-sqs-java-temporary-queues-client/deployments", + "created_at": "2020-09-03T01:34:56Z", + "updated_at": "2020-09-03T01:34:58Z", + "pushed_at": "2020-09-03T01:56:36Z", + "git_url": "git://github.com/iamjpotts/amazon-sqs-java-temporary-queues-client.git", + "ssh_url": "git@github.com:iamjpotts/amazon-sqs-java-temporary-queues-client.git", + "clone_url": "https://github.com/iamjpotts/amazon-sqs-java-temporary-queues-client.git", + "svn_url": "https://github.com/iamjpotts/amazon-sqs-java-temporary-queues-client", + "homepage": null, + "size": 200, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": false, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": false, + "has_discussions": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "apache-2.0", + "name": "Apache License 2.0", + "spdx_id": "Apache-2.0", + "url": "https://api.github.com/licenses/apache-2.0", + "node_id": "MDc6TGljZW5zZTI=" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + + ], + "visibility": "public", + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master" + } +] diff --git a/tests/user_repositories_tests.rs b/tests/user_repositories_tests.rs new file mode 100644 index 00000000..8c8b2e77 --- /dev/null +++ b/tests/user_repositories_tests.rs @@ -0,0 +1,105 @@ +/// Tests API calls related to check runs of a specific commit. +mod mock_error; + +use mock_error::setup_error_handler; +use octocrab::{Error, Octocrab}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use wiremock::{ + matchers::{method, path}, + Mock, MockServer, ResponseTemplate, +}; +use octocrab::models::{Repository, RepositoryId}; + +#[derive(Serialize, Deserialize)] +struct FakePage { + items: Vec, +} + +async fn setup_api(template: ResponseTemplate) -> MockServer { + let mock_server = MockServer::start().await; + + let mocked_path = "/users/some-user/repos"; + + Mock::given(method("GET")) + .and(path(mocked_path)) + .respond_with(template) + .mount(&mock_server) + .await; + setup_error_handler( + &mock_server, + &format!("GET on {mocked_path} was not received"), + ) + .await; + mock_server +} + +fn setup_octocrab(uri: &str) -> Octocrab { + Octocrab::builder().base_uri(uri).unwrap().build().unwrap() +} + +#[tokio::test] +async fn should_return_repositories_for_user() { + let mocked_response: Vec = + serde_json::from_str(include_str!("resources/user_repositories.json")).unwrap(); + let template = ResponseTemplate::new(200).set_body_json(&mocked_response); + let mock_server = setup_api(template).await; + let client = setup_octocrab(&mock_server.uri()); + let result = client + .users("some-user") + .repos() + .send() + .await; + + assert!( + result.is_ok(), + "expected successful result, got error: {:#?}", + result + ); + + let response = result.unwrap(); + let items = response.items; + + assert_eq!(items.len(), 2); + + { + let item = &items[0]; + + assert_eq!(RepositoryId(566109822), item.id); + assert_eq!("actix-examples", item.name); + assert_eq!("Apache-2.0", item.license.as_ref().unwrap().spdx_id); + } + + { + let item = &items[1]; + + assert_eq!(RepositoryId(292435601), item.id); + assert_eq!("amazon-sqs-java-temporary-queues-client", item.name); + assert_eq!("Apache-2.0", item.license.as_ref().unwrap().spdx_id); + } +} + +#[tokio::test] +async fn should_fail_when_not_found() { + let mocked_response = json!({ + "documentation_url": json!("rtm"), + "errors": Value::Null, + "message": json!("Its gone") + }); + + let template = ResponseTemplate::new(404).set_body_json(&mocked_response); + let mock_server = setup_api(template).await; + let client = setup_octocrab(&mock_server.uri()); + let result = client + .users("some-user") + .repos() + .send() + .await; + + match result.unwrap_err() { + Error::GitHub { source, .. } => { + assert_eq!("Its gone", source.message) + }, + other => panic!("Unexpected error: {:?}", other) + } +} \ No newline at end of file