From bf9d32b22975f8e790c764eb9ae3b112df987c05 Mon Sep 17 00:00:00 2001 From: Vaibhav Yenamandra <3663231+envp@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:02:41 -0400 Subject: [PATCH 1/5] gists+examples: Extend `GistsHandler` by adding `star(...)` The `star(...)` function takes a `gist_id` and 'stars' it. Has no observable effect on the gist if it is already starred. --- examples/star_a_gist.rs | 16 ++++++++++++++++ src/api/gists.rs | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 examples/star_a_gist.rs diff --git a/examples/star_a_gist.rs b/examples/star_a_gist.rs new file mode 100644 index 00000000..4fbc618b --- /dev/null +++ b/examples/star_a_gist.rs @@ -0,0 +1,16 @@ +use octocrab::Octocrab; + +#[tokio::main] +async fn main() -> octocrab::Result<()> { + let token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN env variable is required"); + let gist_id = if let Some(gist_id) = std::env::args().nth(1) { + gist_id + } else { + eprintln!("error: Need to pass gist id on argv"); + std::process::exit(1); + }; + + let octocrab = Octocrab::builder().personal_token(token).build()?; + octocrab.gists().star(gist_id).await?; + Ok(()) +} diff --git a/src/api/gists.rs b/src/api/gists.rs index 2e28b340..997c6c09 100644 --- a/src/api/gists.rs +++ b/src/api/gists.rs @@ -122,6 +122,30 @@ impl<'octo> GistsHandler<'octo> { pub fn list_commits(&self, gist_id: impl Into) -> list_commits::ListCommitsBuilder { list_commits::ListCommitsBuilder::new(self, gist_id.into()) } + + /// Star the given gist. See [GitHub API Documentation][docs] more + /// information about response data. + /// + /// ```no_run + /// # async fn run() -> octocrab::Result<()> { + /// octocrab::instance() + /// .gists() + /// .star("00000000000000000000000000000000") + /// .await?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [docs]: https://docs.github.com/en/rest/gists/gists?apiVersion=2022-11-28#star-a-gist + pub async fn star(&self, gist_id: impl AsRef) -> Result<()> { + let gist_id = gist_id.as_ref(); + // PUT here returns an empty body, ignore it since it doesn't make + // sense to deserialize it as JSON. + self.crab + ._put(format!("/gists/{gist_id}/star"), None::<&()>) + .await + .map(|_| ()) + } } #[derive(Debug)] From 53ca14bdd39e89918b7165c619e187b776e47942 Mon Sep 17 00:00:00 2001 From: Vaibhav Yenamandra <3663231+envp@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:27:53 -0400 Subject: [PATCH 2/5] gists+examples: Extend `GistsHandler` by adding `unstar(...)` The `unstar(...)` function takes a `gist_id` and removes a 'star' from it. Has no observable effect on the gist if it is not starred. --- examples/star_a_gist.rs | 47 +++++++++++++++++++++++++++++++++++------ src/api/gists.rs | 24 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/examples/star_a_gist.rs b/examples/star_a_gist.rs index 4fbc618b..be0681b0 100644 --- a/examples/star_a_gist.rs +++ b/examples/star_a_gist.rs @@ -1,16 +1,51 @@ use octocrab::Octocrab; -#[tokio::main] -async fn main() -> octocrab::Result<()> { - let token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN env variable is required"); - let gist_id = if let Some(gist_id) = std::env::args().nth(1) { +struct ProgramArguments { + gist_id: String, + star: bool, +} + +/// Rudimentary CLI interface. Tries to be nice to the caller without too +/// much bloat on the example. +fn parse_argv_or_exit() -> ProgramArguments { + const USAGE: &str = r#"Usage: + (--star | --unstar) GIST_ID"#; + let star = if let Some(param) = std::env::args().nth(1) { + if param == "--star" { + true + } else if param == "--unstar" { + false + } else { + eprintln!("error: Need (--star | --unstar) as first argument."); + eprintln!("{}", USAGE); + std::process::exit(1); + } + } else { + eprintln!("error: Need (--star | --unstar) as first argument."); + eprintln!("{}", USAGE); + std::process::exit(1); + }; + + let gist_id = if let Some(gist_id) = std::env::args().nth(2) { gist_id } else { - eprintln!("error: Need to pass gist id on argv"); + eprintln!("error: Need GIST_ID as second argument."); + eprintln!("{}", USAGE); std::process::exit(1); }; + ProgramArguments { gist_id, star } +} +#[tokio::main] +async fn main() -> octocrab::Result<()> { + let token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN env variable is required"); + let args = parse_argv_or_exit(); let octocrab = Octocrab::builder().personal_token(token).build()?; - octocrab.gists().star(gist_id).await?; + + if args.star { + octocrab.gists().star(args.gist_id).await?; + } else { + octocrab.gists().unstar(args.gist_id).await?; + } Ok(()) } diff --git a/src/api/gists.rs b/src/api/gists.rs index 997c6c09..a5f7108e 100644 --- a/src/api/gists.rs +++ b/src/api/gists.rs @@ -146,6 +146,30 @@ impl<'octo> GistsHandler<'octo> { .await .map(|_| ()) } + + /// Unstar the given gist. See [GitHub API Documentation][docs] more + /// information about response data. + /// + /// ```no_run + /// # async fn run() -> octocrab::Result<()> { + /// octocrab::instance() + /// .gists() + /// .unstar("00000000000000000000000000000000") + /// .await?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [docs]: https://docs.github.com/en/rest/gists/gists?apiVersion=2022-11-28#unstar-a-gist + pub async fn unstar(&self, gist_id: impl AsRef) -> Result<()> { + let gist_id = gist_id.as_ref(); + // DELETE here returns an empty body, ignore it since it doesn't make + // sense to deserialize it as JSON. + self.crab + ._delete(format!("/gists/{gist_id}/star"), None::<&()>) + .await + .map(|_| ()) + } } #[derive(Debug)] From 3ca84344d6f8b4e103541b242050f5b10b3645d6 Mon Sep 17 00:00:00 2001 From: Vaibhav Yenamandra <3663231+envp@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:30:25 -0400 Subject: [PATCH 3/5] examples: Rename star_a_gist -> star_unstar_a_gist --- examples/{star_a_gist.rs => star_unstar_a_gist.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{star_a_gist.rs => star_unstar_a_gist.rs} (100%) diff --git a/examples/star_a_gist.rs b/examples/star_unstar_a_gist.rs similarity index 100% rename from examples/star_a_gist.rs rename to examples/star_unstar_a_gist.rs From 32c39a5db7c6879e9724b3fb5558742da83e3d2d Mon Sep 17 00:00:00 2001 From: Vaibhav Yenamandra <3663231+envp@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:43:14 -0400 Subject: [PATCH 4/5] gists: Add function to check if a gist is starred Create `GistsHandler::is_starred`. This acceepts a `gist_id` and returns if a gist is starred. --- src/api/gists.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/api/gists.rs b/src/api/gists.rs index a5f7108e..40f7c558 100644 --- a/src/api/gists.rs +++ b/src/api/gists.rs @@ -1,6 +1,7 @@ //! The gist API mod list_commits; +use http::StatusCode; use serde::Serialize; use std::collections::BTreeMap; @@ -123,6 +124,31 @@ impl<'octo> GistsHandler<'octo> { list_commits::ListCommitsBuilder::new(self, gist_id.into()) } + /// Check if the given is gist is already starred by the authenticated user. + /// See [GitHub API Documentation][docs] more information about response + /// data. + /// + /// ```no_run + /// # async fn run() -> octocrab::Result<()> { + /// let is_starred: bool = octocrab::instance() + /// .gists() + /// .is_starred("00000000000000000000000000000000") + /// .await?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [docs]: https://docs.github.com/en/rest/gists/gists?apiVersion=2022-11-28#check-if-a-gist-is-starred + pub async fn is_starred(&self, gist_id: impl AsRef) -> Result { + let gist_id = gist_id.as_ref(); + let response = self + .crab + ._get(format!("/gists/{gist_id}/star")) + .await?; + // Gist API returns 204 (NO CONTENT) if a gist is starred + Ok(response.status() == StatusCode::NO_CONTENT) + } + /// Star the given gist. See [GitHub API Documentation][docs] more /// information about response data. /// From ca7cd8d4ecb55f3493f6c8b5bbf375cb7ecf0fd8 Mon Sep 17 00:00:00 2001 From: Vaibhav Yenamandra <3663231+envp@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:53:39 -0400 Subject: [PATCH 5/5] examples: Extend the `star_unstar_a_gist` example This fully demonstrates how to: - Check if a gist is starred - Star a gist - Unstar a gist --- examples/star_unstar_a_gist.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/examples/star_unstar_a_gist.rs b/examples/star_unstar_a_gist.rs index be0681b0..69c82d77 100644 --- a/examples/star_unstar_a_gist.rs +++ b/examples/star_unstar_a_gist.rs @@ -36,16 +36,37 @@ fn parse_argv_or_exit() -> ProgramArguments { ProgramArguments { gist_id, star } } +/// This example tries to demonstrate interacting with a gists' 'stars'. +/// It does so by making a program that takes two CLI arguments: +/// +/// 1) `--star` or `--unstar` to either star/unstar a gist +/// 2) A `GIST_ID` to identify which gist to operate on +/// +/// The example will check if a gist is already starred / unstarred, before +/// performing the operation. #[tokio::main] async fn main() -> octocrab::Result<()> { let token = std::env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN env variable is required"); let args = parse_argv_or_exit(); let octocrab = Octocrab::builder().personal_token(token).build()?; + let gists_handler = octocrab.gists(); + let is_starred = gists_handler.is_starred(&args.gist_id).await?; + + if is_starred && args.star { + println!("{gist_id} is already starred.", gist_id = &args.gist_id); + return Ok(()); + } + if !is_starred && !args.star { + println!("{gist_id} is already un-starred.", gist_id = &args.gist_id); + return Ok(()); + } if args.star { - octocrab.gists().star(args.gist_id).await?; + gists_handler.star(&args.gist_id).await?; + println!("Starred {gist_id}.", gist_id = &args.gist_id) } else { - octocrab.gists().unstar(args.gist_id).await?; + gists_handler.unstar(&args.gist_id).await?; + println!("Un-starred {gist_id}.", gist_id = &args.gist_id) } Ok(()) }