Skip to content

Commit

Permalink
feat: implement delete release
Browse files Browse the repository at this point in the history
  • Loading branch information
loispostula committed Jul 26, 2024
1 parent a5d2afe commit bc78e55
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 32 deletions.
19 changes: 10 additions & 9 deletions src/api/repos/release_assets.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use super::*;
use crate::models::AssetId;

/// Handler for GitHub's releases API.
///
Expand All @@ -18,7 +17,7 @@ impl<'octo, 'r> ReleaseAssetsHandler<'octo, 'r> {
/// let release = octocrab::instance()
/// .repos("owner", "repo")
/// .release_assets()
/// .get(AssetId(3))
/// .get(3)
/// .await?;
/// # Ok(())
/// # }
Expand Down Expand Up @@ -60,20 +59,21 @@ impl<'octo, 'r> ReleaseAssetsHandler<'octo, 'r> {
/// let release = octocrab::instance()
/// .repos("owner", "repo")
/// .release_assets()
/// .delete(AssetId(3))
/// .delete(3)
/// .await?;
/// # Ok(())
/// # }
/// ```
pub async fn delete(&self, id: AssetId) -> Result<()> {
pub async fn delete(&self, id: u64) -> Result<()> {
let route = format!(
"/repos/{owner}/{repo}/releases/assets/{id}",
owner = self.parent.owner,
repo = self.parent.repo,
id = id,
);

self.parent.crab.delete(route, None::<&()>).await
self.parent.crab._delete(route, None::<&()>).await?;
Ok(())
}

/// Streams the binary contents of an asset.
Expand All @@ -97,7 +97,7 @@ impl<'octo, 'r> ReleaseAssetsHandler<'octo, 'r> {
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
pub async fn stream(
&self,
id: AssetId,
id: u64,
) -> crate::Result<impl futures_core::Stream<Item = crate::Result<bytes::Bytes>>> {
use futures_util::TryStreamExt;
//use snafu::GenerateImplicitData;
Expand Down Expand Up @@ -132,6 +132,7 @@ impl<'octo, 'r> ReleaseAssetsHandler<'octo, 'r> {
pub struct UpdateReleaseAssetBuilder<'octo, 'repos, 'handler, 'name, 'label> {
#[serde(skip)]
handler: &'handler ReleaseAssetsHandler<'octo, 'repos>,
#[serde(skip)]
asset_id: u64,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<&'name str>,
Expand All @@ -158,13 +159,13 @@ impl<'octo, 'repos, 'handler, 'name, 'label, 'state>
}

/// The name of the release asset.
pub fn tag_name(mut self, name: &'name (impl AsRef<str> + ?Sized)) -> Self {
pub fn name(mut self, name: &'name (impl AsRef<str> + ?Sized)) -> Self {
self.name = Some(name.as_ref());
self
}

/// The label of the release asset.
pub fn name(mut self, label: &'label (impl AsRef<str> + ?Sized)) -> Self {
pub fn label(mut self, label: &'label (impl AsRef<str> + ?Sized)) -> Self {
self.label = Some(label.as_ref());
self
}
Expand All @@ -181,7 +182,7 @@ impl<'octo, 'repos, 'handler, 'name, 'label, 'state>
/// Sends the actual request.
pub async fn send(self) -> crate::Result<crate::models::repos::Asset> {
let route = format!(
"/repos/{owner}/{repo}/releases/{asset_id}",
"/repos/{owner}/{repo}/releases/assets/{asset_id}",
owner = self.handler.parent.owner,
repo = self.handler.parent.repo,
asset_id = self.asset_id,
Expand Down
75 changes: 55 additions & 20 deletions src/api/repos/releases.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::*;
use crate::error::{UriParseError, UriParseSnafu};
use crate::from_response::FromResponse;
use crate::{body::OctoBody, models::repos::Asset};
use crate::models::repos::Asset;
use std::convert::TryInto;

/// Handler for GitHub's releases API.
///
Expand Down Expand Up @@ -189,15 +191,13 @@ impl<'octo, 'r> ReleasesHandler<'octo, 'r> {
/// Upload an [`crate::models::repos::Asset`] associated with
/// a [`crate::models::repos::Release`]
/// ```no_run
/// use bytes::Bytes;
/// # async fn run() -> octocrab::Result<()> {
/// let file_path = std::path::Path::new("/tmp/my_asset.tar.gz");
/// let file_size = unwrap!(std::fs::metadata(file_path)).len();
/// let file = unwrap!(tokio::fs::File::open(file).await);
/// let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new());
/// let file_data: Bytes = Bytes::from("some_data");
/// let asset = octocrab::instance()
/// .repos("owner", "repo")
/// .releases()
/// .upload_asset(1, "my_asset.tar.gz", stream)
/// .upload_asset(1, "my_asset.tar.gz", file_data)
/// .label("My Awesome Asset")
/// .send()
/// .await?;
Expand All @@ -220,7 +220,7 @@ impl<'octo, 'r> ReleasesHandler<'octo, 'r> {
/// # let octocrab = octocrab::Octocrab::default();
/// let page = octocrab.repos("owner", "repo")
/// .releases()
/// .assets()
/// .assets(1)
/// // Optional Parameters
/// .per_page(100)
/// .page(5u32)
Expand All @@ -230,8 +230,8 @@ impl<'octo, 'r> ReleasesHandler<'octo, 'r> {
/// # Ok(())
/// # }
/// ```
pub fn assets(&self) -> ListReleaseAssetsBuilder<'_, '_, '_> {
ListReleaseAssetsBuilder::new(self)
pub fn assets(&self, release_id: u64) -> ListReleaseAssetsBuilder<'_, '_, '_> {
ListReleaseAssetsBuilder::new(self, release_id)
}

/// Streams the binary contents of an asset.
Expand All @@ -256,10 +256,33 @@ impl<'octo, 'r> ReleasesHandler<'octo, 'r> {
#[deprecated(note = "use repos::ReleaseAssetsHandler::stream instead")]
pub async fn stream_asset(
&self,
asset_id: AssetId,
asset_id: u64,
) -> crate::Result<impl futures_core::Stream<Item = crate::Result<bytes::Bytes>>> {
self.parent.release_assets().stream(asset_id).await
}

/// Delete a release using its id.
/// ```no_run
/// # async fn run() -> octocrab::Result<()> {
/// let release = octocrab::instance()
/// .repos("owner", "repo")
/// .releases()
/// .delete(3)
/// .await?;
/// # Ok(())
/// # }
/// ```
pub async fn delete(&self, id: u64) -> Result<()> {
let route = format!(
"/repos/{owner}/{repo}/releases/{id}",
owner = self.parent.owner,
repo = self.parent.repo,
id = id,
);

self.parent.crab._delete(route, None::<&()>).await?;
Ok(())
}
}

/// A builder pattern struct for listing releases.
Expand Down Expand Up @@ -636,16 +659,19 @@ impl<
pub struct ListReleaseAssetsBuilder<'octo, 'r1, 'r2> {
#[serde(skip)]
handler: &'r2 ReleasesHandler<'octo, 'r1>,
#[serde(skip)]
release_id: u64,
#[serde(skip_serializing_if = "Option::is_none")]
per_page: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
page: Option<u32>,
}

impl<'octo, 'r1, 'r2> ListReleaseAssetsBuilder<'octo, 'r1, 'r2> {
pub(crate) fn new(handler: &'r2 ReleasesHandler<'octo, 'r1>) -> Self {
pub(crate) fn new(handler: &'r2 ReleasesHandler<'octo, 'r1>, release_id: u64) -> Self {
Self {
handler,
release_id,
per_page: None,
page: None,
}
Expand All @@ -666,9 +692,10 @@ impl<'octo, 'r1, 'r2> ListReleaseAssetsBuilder<'octo, 'r1, 'r2> {
/// Sends the actual request.
pub async fn send(self) -> crate::Result<crate::Page<crate::models::repos::Asset>> {
let route = format!(
"/repos/{owner}/{repo}/releases/assets",
"/repos/{owner}/{repo}/releases/{release_id}/assets",
owner = self.handler.parent.owner,
repo = self.handler.parent.repo
repo = self.handler.parent.repo,
release_id = self.release_id,
);
self.handler.parent.crab.get(route, Some(&self)).await
}
Expand Down Expand Up @@ -715,17 +742,25 @@ impl<'octo, 'repos, 'handler, 'name, 'label>
// then he will not have access to upload to it.
let release = self.handler.get(self.release_id).await?;

// Documentation tells us to take the `upload_url`, but `upload_url` is just `assets_url` with `{?name,label}`.
let mut url = release.assets_url.clone();
url.query_pairs_mut().clear().append_pair("name", self.name);
let mut base_uri = format!(
"{}?name={}",
release.upload_url.replace("{?name,label}", ""),
self.name
);
if let Some(label) = self.label {
url.query_pairs_mut().append_pair("label", label);
base_uri = format!("{}&label={}", base_uri, label);
}

let url: Uri = base_uri
.try_into()
.map_err(|_| UriParseError {})
.context(UriParseSnafu)?;
let request = Builder::new()
.method(http::Method::POST)
.uri(url.to_string())
.header(http::header::ACCEPT, "application/octet-stream")
.body(OctoBody::from(self.body))
.uri(url)
.header(http::header::CONTENT_TYPE, "application/octet-stream")
.header(http::header::CONTENT_LENGTH, self.body.len())
.body(self.body)
.context(HttpSnafu)?;
let response = self.handler.parent.crab.execute(request).await?;
Asset::from_response(crate::map_github_error(response).await?).await
Expand Down
4 changes: 1 addition & 3 deletions tests/repos_releases_list_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ async fn setup_get_api(template: ResponseTemplate) -> MockServer {
let mock_server = MockServer::start().await;

Mock::given(method("GET"))
.and(path(format!(
"/repos/{OWNER}/{REPO}/releases"
)))
.and(path(format!("/repos/{OWNER}/{REPO}/releases")))
.respond_with(template)
.mount(&mock_server)
.await;
Expand Down

0 comments on commit bc78e55

Please sign in to comment.