Skip to content

Commit

Permalink
refactor: improve github api (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilrobot-01 authored May 14, 2024
1 parent 4434e99 commit b2623d2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 54 deletions.
8 changes: 4 additions & 4 deletions crates/pop-cli/src/commands/new/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,17 +263,17 @@ fn check_destination_path(name_template: &String) -> Result<&Path> {
}

async fn get_latest_3_releases(url: url::Url) -> Result<Vec<Release>> {
let api_url = GitHub::url_api_releases(&url)?;
let mut latest_3_releases: Vec<Release> = GitHub::get_latest_releases(api_url)
let repo = GitHub::parse(url.as_str())?;
let mut latest_3_releases: Vec<Release> = repo
.get_latest_releases()
.await?
.into_iter()
.filter(|r| !r.prerelease)
.take(3)
.collect();
// Get the commit sha for the releases
for release in latest_3_releases.iter_mut() {
let api_url = GitHub::url_api_tag_information(&url, &release.tag_name)?;
let commit = GitHub::get_commit_sha_from_release(api_url).await?;
let commit = repo.get_commit_sha_from_release(&release.tag_name).await?;
release.commit = Some(commit);
}
Ok(latest_3_releases)
Expand Down
5 changes: 2 additions & 3 deletions crates/pop-parachains/src/up.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,8 @@ impl Zombienet {
}

async fn latest_polkadot_release() -> Result<String, Error> {
let repo = Url::parse(POLKADOT_SDK).expect("repository url valid");
let api_url = GitHub::url_api_releases(&repo)?;
match GitHub::get_latest_releases(api_url).await {
let repo = GitHub::parse(POLKADOT_SDK)?;
match repo.get_latest_releases().await {
Ok(releases) => {
// Fetching latest releases
for release in releases {
Expand Down
110 changes: 63 additions & 47 deletions crates/pop-parachains/src/utils/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,24 +142,46 @@ impl Git {
}
}

pub struct GitHub;
pub struct GitHub {
pub org: String,
pub name: String,
api: String,
}

impl GitHub {
const GITHUB: &'static str = "github.com";
pub async fn get_latest_releases(api_url: String) -> Result<Vec<Release>> {

pub fn parse(url: &str) -> Result<Self> {
let url = Url::parse(url)?;
Ok(Self {
org: Self::org(&url)?.into(),
name: Self::name(&url)?.into(),
api: "https://api.github.com".into(),
})
}

// Overrides the api base url for testing
#[cfg(test)]
fn with_api(mut self, api: impl Into<String>) -> Self {
self.api = api.into();
self
}

pub async fn get_latest_releases(&self) -> Result<Vec<Release>> {
static APP_USER_AGENT: &str =
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
let client = reqwest::ClientBuilder::new().user_agent(APP_USER_AGENT).build()?;
let response = client.get(api_url).send().await?;
let url = self.api_releases_url();
let response = client.get(url).send().await?;
Ok(response.json::<Vec<Release>>().await?)
}

pub async fn get_commit_sha_from_release(api_url: String) -> Result<String> {
pub async fn get_commit_sha_from_release(&self, tag_name: &str) -> Result<String> {
static APP_USER_AGENT: &str =
concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

let client = reqwest::ClientBuilder::new().user_agent(APP_USER_AGENT).build()?;

let response = client.get(api_url).send().await?;
let response = client.get(self.api_tag_information(tag_name)).send().await?;
let value = response.json::<serde_json::Value>().await?;
let commit = value
.get("object")
Expand All @@ -170,20 +192,12 @@ impl GitHub {
Ok(commit)
}

pub fn url_api_releases(repo: &Url) -> Result<String> {
Ok(format!(
"https://api.github.com/repos/{}/{}/releases",
Self::org(repo)?,
Self::name(repo)?
))
fn api_releases_url(&self) -> String {
format!("{}/repos/{}/{}/releases", self.api, self.org, self.name)
}
pub fn url_api_tag_information(repo: &Url, tag_name: &str) -> Result<String> {
Ok(format!(
"https://api.github.com/repos/{}/{}/git/ref/tags/{}",
Self::org(repo)?,
Self::name(repo)?,
tag_name
))

fn api_tag_information(&self, tag_name: &str) -> String {
format!("{}/repos/{}/{}/git/ref/tags/{}", self.api, self.org, self.name, tag_name)
}

fn org(repo: &Url) -> Result<&str> {
Expand All @@ -209,12 +223,13 @@ impl GitHub {
pub(crate) fn release(repo: &Url, tag: &str, artifact: &str) -> String {
format!("{}/releases/download/{tag}/{artifact}", repo.as_str())
}

pub(crate) fn convert_to_ssh_url(url: &Url) -> String {
format!("git@{}:{}.git", url.host_str().unwrap_or(Self::GITHUB), &url.path()[1..])
}
}

#[derive(serde::Deserialize)]
#[derive(Debug, PartialEq, serde::Deserialize)]
pub struct Release {
pub tag_name: String,
pub name: String,
Expand All @@ -230,18 +245,19 @@ mod tests {
const BASE_PARACHAIN: &str = "https://github.com/r0gue-io/base-parachain";
const POLKADOT_SDK: &str = "https://github.com/paritytech/polkadot-sdk";

async fn releases_mock(mock_server: &mut Server, payload: String) -> Mock {
async fn releases_mock(mock_server: &mut Server, repo: &GitHub, payload: &str) -> Mock {
mock_server
.mock("GET", "/releases")
.mock("GET", format!("/repos/{}/{}/releases", repo.org, repo.name).as_str())
.with_status(200)
.with_header("content-type", "application/json")
.with_body(payload)
.create_async()
.await
}
async fn tag_mock(mock_server: &mut Server, payload: String) -> Mock {

async fn tag_mock(mock_server: &mut Server, repo: &GitHub, tag: &str, payload: &str) -> Mock {
mock_server
.mock("GET", "/polkadot-v1.11.0")
.mock("GET", format!("/repos/{}/{}/git/ref/tags/{tag}", repo.org, repo.name).as_str())
.with_status(200)
.with_header("content-type", "application/json")
.with_body(payload)
Expand All @@ -251,30 +267,33 @@ mod tests {

#[tokio::test]
async fn test_get_latest_releases() -> Result<(), Box<dyn std::error::Error>> {
let mut mock_server = mockito::Server::new_async().await;
let mut mock_server = Server::new_async().await;

let mut endpoint = mock_server.url();
endpoint.push_str("/releases");
let expected_payload = r#"[{
"tag_name": "polkadot-v1.10.0",
"name": "Polkadot v1.10.0",
"prerelease": false
}]"#;
let mock = releases_mock(&mut mock_server, expected_payload.to_string()).await;
let latest_release = GitHub::get_latest_releases(endpoint).await?;
assert_eq!(latest_release[0].name, "Polkadot v1.10.0");
assert_eq!(latest_release[0].tag_name, "polkadot-v1.10.0");
assert_eq!(latest_release[0].prerelease, false);
let repo = GitHub::parse(BASE_PARACHAIN)?.with_api(&mock_server.url());
let mock = releases_mock(&mut mock_server, &repo, expected_payload).await;
let latest_release = repo.get_latest_releases().await?;
assert_eq!(
latest_release[0],
Release {
tag_name: "polkadot-v1.10.0".to_string(),
name: "Polkadot v1.10.0".into(),
prerelease: false,
commit: None
}
);
mock.assert_async().await;
Ok(())
}

#[tokio::test]
async fn get_releases_with_commit_sha() -> Result<(), Box<dyn std::error::Error>> {
let mut mock_server = mockito::Server::new_async().await;
let mut mock_server = Server::new_async().await;

let mut endpoint = mock_server.url();
endpoint.push_str("/polkadot-v1.11.0");
let expected_payload = r#"{
"ref": "refs/tags/polkadot-v1.11.0",
"node_id": "REF_kwDOKDT1SrpyZWZzL3RhZ3MvcG9sa2Fkb3QtdjEuMTEuMA",
Expand All @@ -285,38 +304,35 @@ mod tests {
"url": "https://api.github.com/repos/paritytech/polkadot-sdk/git/commits/0bb6249268c0b77d2834640b84cb52fdd3d7e860"
}
}"#;
let mock = tag_mock(&mut mock_server, expected_payload.to_string()).await;
let hash = GitHub::get_commit_sha_from_release(endpoint).await?;
let repo = GitHub::parse(BASE_PARACHAIN)?.with_api(&mock_server.url());
let mock = tag_mock(&mut mock_server, &repo, "polkadot-v1.11.0", expected_payload).await;
let hash = repo.get_commit_sha_from_release("polkadot-v1.11.0").await?;
assert_eq!(hash, "0bb6249268c0b77d2834640b84cb52fdd3d7e860");
mock.assert_async().await;
Ok(())
}

#[test]
fn test_get_releases_api_url() -> Result<(), Box<dyn std::error::Error>> {
let url = Url::parse(POLKADOT_SDK)?;
let api_url = GitHub::url_api_releases(&url)?;
assert_eq!(api_url, "https://api.github.com/repos/paritytech/polkadot-sdk/releases");
assert_eq!(
GitHub::parse(POLKADOT_SDK)?.api_releases_url(),
"https://api.github.com/repos/paritytech/polkadot-sdk/releases"
);
Ok(())
}

#[test]
fn test_url_api_tag_information() -> Result<(), Box<dyn std::error::Error>> {
let url = Url::parse(POLKADOT_SDK)?;
let tag = "polkadot-v1.11.0";
let api_url = GitHub::url_api_tag_information(&url, tag)?;
assert_eq!(
api_url,
GitHub::parse(POLKADOT_SDK)?.api_tag_information("polkadot-v1.11.0"),
"https://api.github.com/repos/paritytech/polkadot-sdk/git/ref/tags/polkadot-v1.11.0"
);
Ok(())
}

#[test]
fn test_parse_org() -> Result<(), Box<dyn std::error::Error>> {
let url = Url::parse(BASE_PARACHAIN)?;
let org = GitHub::org(&url)?;
assert_eq!(org, "r0gue-io");
assert_eq!(GitHub::parse(BASE_PARACHAIN)?.org, "r0gue-io");
Ok(())
}

Expand Down

0 comments on commit b2623d2

Please sign in to comment.