Skip to content

Commit

Permalink
Fix Zenodo license api's bug and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
suecharo committed Jan 29, 2024
1 parent aae8566 commit 07166ea
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 83 deletions.
130 changes: 66 additions & 64 deletions src/gh/api.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::gh;

use anyhow::{anyhow, bail, Result};
use base64::{engine::general_purpose, Engine as _};
use serde_json::json;
use serde_json::Value;
use std::collections::HashMap;
Expand All @@ -27,35 +28,35 @@ pub fn get_default_branch(
name: impl AsRef<str>,
memo: Option<&mut HashMap<String, String>>,
) -> Result<String> {
let err_message = "Failed to parse the response to get the default branch";
match memo {
Some(memo) => {
let key = format!("{}/{}", owner.as_ref(), name.as_ref());
match memo.get(&key) {
Some(default_branch) => Ok(default_branch.to_string()),
None => {
let res = get_repos(gh_token, owner, name)?;
let default_branch = res
.get("default_branch")
.ok_or_else(|| anyhow!(err_message))?
.as_str()
.ok_or_else(|| anyhow!(err_message))?
.to_string();
memo.insert(key, default_branch.clone());
Ok(default_branch)
}
}
}
None => {
let res = get_repos(gh_token, owner, name)?;
Ok(res
.get("default_branch")
.ok_or_else(|| anyhow!(err_message))?
.as_str()
.ok_or_else(|| anyhow!(err_message))?
.to_string())
let key = format!("{}/{}", owner.as_ref(), name.as_ref());

if let Some(ref memo) = memo {
if let Some(default_branch) = memo.get(&key) {
return Ok(default_branch.to_string());
}
}

let default_branch = get_default_branch_from_repo(&gh_token, &owner, &name)?;
if let Some(memo) = memo {
memo.insert(key, default_branch.clone());
}

Ok(default_branch)
}

fn get_default_branch_from_repo(
gh_token: impl AsRef<str>,
owner: impl AsRef<str>,
name: impl AsRef<str>,
) -> Result<String> {
let res = get_repos(gh_token, owner, name)?;
let err_message = "Failed to parse the response to get the default branch";
Ok(res
.get("default_branch")
.ok_or_else(|| anyhow!(err_message))?
.as_str()
.ok_or_else(|| anyhow!(err_message))?
.to_string())
}

/// https://docs.github.com/ja/rest/reference/branches#get-a-branch
Expand All @@ -81,44 +82,45 @@ pub fn get_latest_commit_sha(
branch_name: impl AsRef<str>,
memo: Option<&mut HashMap<String, String>>,
) -> Result<String> {
let err_message = "Failed to parse the response to get a latest commit sha";
match memo {
Some(memo) => {
let key = format!(
"{}/{}/{}",
owner.as_ref(),
name.as_ref(),
branch_name.as_ref()
);
match memo.get(&key) {
Some(latest_commit_hash) => Ok(latest_commit_hash.to_string()),
None => {
let res = get_branches(gh_token, owner, name, branch_name)?;
let latest_commit_hash = res
.get("commit")
.ok_or_else(|| anyhow!(err_message))?
.get("sha")
.ok_or_else(|| anyhow!(err_message))?
.as_str()
.ok_or_else(|| anyhow!(err_message))?
.to_string();
memo.insert(key, latest_commit_hash.clone());
Ok(latest_commit_hash)
}
}
}
None => {
let res = get_branches(gh_token, owner, name, branch_name)?;
Ok(res
.get("commit")
.ok_or_else(|| anyhow!(err_message))?
.get("sha")
.ok_or_else(|| anyhow!(err_message))?
.as_str()
.ok_or_else(|| anyhow!(err_message))?
.to_string())
let key = format!(
"{}/{}/{}",
owner.as_ref(),
name.as_ref(),
branch_name.as_ref()
);

if let Some(ref memo) = memo {
if let Some(latest_commit_hash) = memo.get(&key) {
return Ok(latest_commit_hash.to_string());
}
}

let latest_commit_hash = get_latest_commit_sha_from_branch(gh_token, owner, name, branch_name)?;
if let Some(memo) = memo {
memo.insert(key, latest_commit_hash.clone());
}

Ok(latest_commit_hash)
}

fn get_latest_commit_sha_from_branch(
gh_token: impl AsRef<str>,
owner: impl AsRef<str>,
name: impl AsRef<str>,
branch_name: impl AsRef<str>,
) -> Result<String> {
let err_message = "Failed to parse the response to get a latest commit sha";
let res = get_branches(gh_token, owner, name, branch_name)?;
let latest_commit_hash = res
.get("commit")
.ok_or_else(|| anyhow!(err_message))?
.get("sha")
.ok_or_else(|| anyhow!(err_message))?
.as_str()
.ok_or_else(|| anyhow!(err_message))?
.to_string();

Ok(latest_commit_hash)
}

/// https://docs.github.com/ja/rest/reference/users#get-a-user
Expand Down Expand Up @@ -588,7 +590,7 @@ pub fn create_or_update_file(
content: impl AsRef<str>,
branch: impl AsRef<str>,
) -> Result<()> {
let encoded_content = base64::encode(content.as_ref());
let encoded_content = general_purpose::STANDARD.encode(content.as_ref());
let body = match get_contents_blob_sha(&gh_token, &owner, &name, &path, &branch) {
Ok(blob) => {
// If the file already exists, update it
Expand Down
36 changes: 17 additions & 19 deletions src/sub_cmd/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use crate::gh;
use crate::metadata;
use crate::remote;

use anyhow::Context;
use anyhow::{anyhow, bail, ensure, Result};
use log::debug;
use regex::Regex;
use serde::Deserialize;
use std::collections::{HashMap, HashSet};
use url::Url;

Expand Down Expand Up @@ -42,12 +44,18 @@ pub fn validate_version(version: impl AsRef<str>) -> Result<()> {
/// Change the license to `spdx_id`
/// e.g., `apache-2.0` -> `Apache-2.0`
fn validate_license(meta: &mut metadata::types::Metadata, gh_token: impl AsRef<str>) -> Result<()> {
let spdx_id = validate_with_github_license_api(gh_token, &meta.license)?;
let spdx_id: String = validate_with_github_license_api(gh_token, &meta.license)?;
validate_with_zenodo_license_api(&spdx_id)?;
meta.license = spdx_id;
Ok(())
}

#[derive(Debug, Deserialize)]
struct LicenseResponse {
permissions: Vec<String>,
spdx_id: String,
}

/// https://docs.github.com/ja/rest/reference/licenses#get-a-license
/// Ensure that `distribution` is included in `permissions` field.
fn validate_with_github_license_api(
Expand All @@ -59,28 +67,19 @@ fn validate_with_github_license_api(
license.as_ref()
))?;
let res = gh::get_request(gh_token, &url, &[])?;
let err_msg = "`license` is not valid from GitHub license API";
let permissions = res
.get("permissions")
.ok_or_else(|| anyhow!(err_msg))?
.as_array()
.ok_or_else(|| anyhow!(err_msg))?
.iter()
.map(|v| v.as_str().ok_or_else(|| anyhow!(err_msg)))
.collect::<Result<Vec<_>>>()?;
ensure!(permissions.contains(&"distribution"), err_msg);
let spdx_id = res
.get("spdx_id")
.ok_or_else(|| anyhow!(err_msg))?
.as_str()
.ok_or_else(|| anyhow!(err_msg))?;
Ok(spdx_id.to_string())
let res: LicenseResponse =
serde_json::from_value(res).context("Failed to parse GitHub license API response")?;
ensure!(
res.permissions.contains(&String::from("distribution")),
"GitHub license API response does not contain `distribution` in `permissions` field"
);
Ok(res.spdx_id)
}

/// https://developers.zenodo.org/?shell#retrieve41
fn validate_with_zenodo_license_api(license: impl AsRef<str>) -> Result<()> {
let url = Url::parse(&format!(
"https://zenodo.org/api/licenses/{}",
"https://zenodo.org/api/vocabularies/licenses/{}",
license.as_ref()
))?;
// Return the path for this URL, as a percent-encoded ASCII string
Expand Down Expand Up @@ -221,7 +220,6 @@ mod tests {
fn test_validate_with_zenodo_license_api() -> Result<()> {
validate_with_zenodo_license_api("cc0-1.0")?;
validate_with_zenodo_license_api("mit")?;
validate_with_zenodo_license_api("MIT")?;
validate_with_zenodo_license_api("apache-2.0")?;
Ok(())
}
Expand Down

0 comments on commit 07166ea

Please sign in to comment.