#![allow(
clippy::all
)]
use serde::Deserialize;
use roctokit::adapters::{AdapterError, Client, GitHubRequest, GitHubResponseExt};
use crate::models::*;
use super::PerPage;
use std::collections::HashMap;
use serde_json::value::Value;
pub struct DependencyGraph<'api, C: Client> where AdapterError: From<<C as Client>::Err> {
client: &'api C
}
pub fn new<C: Client>(client: &C) -> DependencyGraph<C> where AdapterError: From<<C as Client>::Err> {
DependencyGraph { client }
}
#[derive(Debug, thiserror::Error)]
pub enum DependencyGraphCreateRepositorySnapshotError {
#[error("Status code: {}", code)]
Generic { code: u16 },
}
impl From<DependencyGraphCreateRepositorySnapshotError> for AdapterError {
fn from(err: DependencyGraphCreateRepositorySnapshotError) -> Self {
let (description, status_code) = match err {
DependencyGraphCreateRepositorySnapshotError::Generic { code } => (String::from("Generic"), code)
};
Self::Endpoint {
description,
status_code,
source: Some(Box::new(err))
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum DependencyGraphDiffRangeError {
#[error("Resource not found")]
Status404(BasicError),
#[error("Response for a private repository when GitHub Advanced Security is not enabled, or if used against a fork")]
Status403(BasicError),
#[error("Status code: {}", code)]
Generic { code: u16 },
}
impl From<DependencyGraphDiffRangeError> for AdapterError {
fn from(err: DependencyGraphDiffRangeError) -> Self {
let (description, status_code) = match err {
DependencyGraphDiffRangeError::Status404(_) => (String::from("Resource not found"), 404),
DependencyGraphDiffRangeError::Status403(_) => (String::from("Response for a private repository when GitHub Advanced Security is not enabled, or if used against a fork"), 403),
DependencyGraphDiffRangeError::Generic { code } => (String::from("Generic"), code)
};
Self::Endpoint {
description,
status_code,
source: Some(Box::new(err))
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum DependencyGraphExportSbomError {
#[error("Resource not found")]
Status404(BasicError),
#[error("Forbidden")]
Status403(BasicError),
#[error("Status code: {}", code)]
Generic { code: u16 },
}
impl From<DependencyGraphExportSbomError> for AdapterError {
fn from(err: DependencyGraphExportSbomError) -> Self {
let (description, status_code) = match err {
DependencyGraphExportSbomError::Status404(_) => (String::from("Resource not found"), 404),
DependencyGraphExportSbomError::Status403(_) => (String::from("Forbidden"), 403),
DependencyGraphExportSbomError::Generic { code } => (String::from("Generic"), code)
};
Self::Endpoint {
description,
status_code,
source: Some(Box::new(err))
}
}
}
#[derive(Default, Serialize)]
pub struct DependencyGraphDiffRangeParams<'req> {
name: Option<&'req str>
}
impl<'req> DependencyGraphDiffRangeParams<'req> {
pub fn new() -> Self {
Self::default()
}
pub fn name(self, name: &'req str) -> Self {
Self {
name: Some(name),
}
}
}
impl<'api, C: Client> DependencyGraph<'api, C> where AdapterError: From<<C as Client>::Err> {
pub async fn create_repository_snapshot_async(&self, owner: &str, repo: &str, body: PostDependencyGraphCreateRepositorySnapshot) -> Result<PostDependencyGraphCreateRepositorySnapshotResponse201, AdapterError> {
let request_uri = format!("{}/repos/{}/{}/dependency-graph/snapshots", super::GITHUB_BASE_API_URL, owner, repo);
let req = GitHubRequest {
uri: request_uri,
body: Some(C::from_json::<PostDependencyGraphCreateRepositorySnapshot>(body)?),
method: "POST",
headers: vec![]
};
let request = self.client.build(req)?;
let github_response = self.client.fetch_async(request).await?;
if github_response.is_success() {
Ok(github_response.to_json_async().await?)
} else {
match github_response.status_code() {
code => Err(DependencyGraphCreateRepositorySnapshotError::Generic { code }.into()),
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn create_repository_snapshot(&self, owner: &str, repo: &str, body: PostDependencyGraphCreateRepositorySnapshot) -> Result<PostDependencyGraphCreateRepositorySnapshotResponse201, AdapterError> {
let request_uri = format!("{}/repos/{}/{}/dependency-graph/snapshots", super::GITHUB_BASE_API_URL, owner, repo);
let req = GitHubRequest {
uri: request_uri,
body: Some(C::from_json::<PostDependencyGraphCreateRepositorySnapshot>(body)?),
method: "POST",
headers: vec![]
};
let request = self.client.build(req)?;
let github_response = self.client.fetch(request)?;
if github_response.is_success() {
Ok(github_response.to_json()?)
} else {
match github_response.status_code() {
code => Err(DependencyGraphCreateRepositorySnapshotError::Generic { code }.into()),
}
}
}
pub async fn diff_range_async(&self, owner: &str, repo: &str, basehead: &str, query_params: Option<impl Into<DependencyGraphDiffRangeParams<'api>>>) -> Result<DependencyGraphDiff, AdapterError> {
let mut request_uri = format!("{}/repos/{}/{}/dependency-graph/compare/{}", super::GITHUB_BASE_API_URL, owner, repo, basehead);
if let Some(params) = query_params {
request_uri.push_str("?");
request_uri.push_str(&serde_urlencoded::to_string(params.into())?);
}
let req = GitHubRequest {
uri: request_uri,
body: None::<C::Body>,
method: "GET",
headers: vec![]
};
let request = self.client.build(req)?;
let github_response = self.client.fetch_async(request).await?;
if github_response.is_success() {
Ok(github_response.to_json_async().await?)
} else {
match github_response.status_code() {
404 => Err(DependencyGraphDiffRangeError::Status404(github_response.to_json_async().await?).into()),
403 => Err(DependencyGraphDiffRangeError::Status403(github_response.to_json_async().await?).into()),
code => Err(DependencyGraphDiffRangeError::Generic { code }.into()),
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn diff_range(&self, owner: &str, repo: &str, basehead: &str, query_params: Option<impl Into<DependencyGraphDiffRangeParams<'api>>>) -> Result<DependencyGraphDiff, AdapterError> {
let mut request_uri = format!("{}/repos/{}/{}/dependency-graph/compare/{}", super::GITHUB_BASE_API_URL, owner, repo, basehead);
if let Some(params) = query_params {
request_uri.push_str("?");
let qp: DependencyGraphDiffRangeParams = params.into();
request_uri.push_str(&serde_urlencoded::to_string(qp)?);
}
let req = GitHubRequest {
uri: request_uri,
body: None,
method: "GET",
headers: vec![]
};
let request = self.client.build(req)?;
let github_response = self.client.fetch(request)?;
if github_response.is_success() {
Ok(github_response.to_json()?)
} else {
match github_response.status_code() {
404 => Err(DependencyGraphDiffRangeError::Status404(github_response.to_json()?).into()),
403 => Err(DependencyGraphDiffRangeError::Status403(github_response.to_json()?).into()),
code => Err(DependencyGraphDiffRangeError::Generic { code }.into()),
}
}
}
pub async fn export_sbom_async(&self, owner: &str, repo: &str) -> Result<DependencyGraphSpdxSbom, AdapterError> {
let request_uri = format!("{}/repos/{}/{}/dependency-graph/sbom", super::GITHUB_BASE_API_URL, owner, repo);
let req = GitHubRequest {
uri: request_uri,
body: None::<C::Body>,
method: "GET",
headers: vec![]
};
let request = self.client.build(req)?;
let github_response = self.client.fetch_async(request).await?;
if github_response.is_success() {
Ok(github_response.to_json_async().await?)
} else {
match github_response.status_code() {
404 => Err(DependencyGraphExportSbomError::Status404(github_response.to_json_async().await?).into()),
403 => Err(DependencyGraphExportSbomError::Status403(github_response.to_json_async().await?).into()),
code => Err(DependencyGraphExportSbomError::Generic { code }.into()),
}
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn export_sbom(&self, owner: &str, repo: &str) -> Result<DependencyGraphSpdxSbom, AdapterError> {
let request_uri = format!("{}/repos/{}/{}/dependency-graph/sbom", super::GITHUB_BASE_API_URL, owner, repo);
let req = GitHubRequest {
uri: request_uri,
body: None,
method: "GET",
headers: vec![]
};
let request = self.client.build(req)?;
let github_response = self.client.fetch(request)?;
if github_response.is_success() {
Ok(github_response.to_json()?)
} else {
match github_response.status_code() {
404 => Err(DependencyGraphExportSbomError::Status404(github_response.to_json()?).into()),
403 => Err(DependencyGraphExportSbomError::Status403(github_response.to_json()?).into()),
code => Err(DependencyGraphExportSbomError::Generic { code }.into()),
}
}
}
}