-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
registry: fetch & serve GitHub READMEs (#481)
- Loading branch information
Showing
14 changed files
with
294 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
CREATE TABLE IF NOT EXISTS readmes ( | ||
id BIGSERIAL PRIMARY KEY, | ||
extension_id INT4 UNIQUE NOT NULL, | ||
readme_html TEXT NOT NULL | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
use reqwest::Client; | ||
|
||
use crate::{ | ||
errors::{ExtensionRegistryError, Result}, | ||
repository::Registry, | ||
}; | ||
|
||
pub struct GithubApiClient { | ||
token: String, | ||
client: Client, | ||
} | ||
|
||
impl GithubApiClient { | ||
pub fn new(token: String) -> Self { | ||
Self { | ||
token, | ||
client: Client::new(), | ||
} | ||
} | ||
|
||
pub async fn fetch_readme(&self, project_url: &str) -> Result<String> { | ||
// TODO: deal with error | ||
let project = GitHubProject::parse_url(project_url).unwrap(); | ||
|
||
let readme_url = project.build_readme_url(); | ||
|
||
self.client | ||
.get(readme_url) | ||
.header("Accept", "application/vnd.github.html") | ||
.header("X-GitHub-Api-Version", "2022-11-28") | ||
.header("User-Agent", "request") | ||
.bearer_auth(&self.token) | ||
.send() | ||
.await? | ||
.text() | ||
.await | ||
.map_err(Into::into) | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
struct GitHubProject<'a> { | ||
owner: &'a str, | ||
name: &'a str, | ||
subdir: Option<&'a str>, | ||
} | ||
|
||
impl<'a> GitHubProject<'a> { | ||
pub fn parse_url(url: &'a str) -> Option<Self> { | ||
let remaining = url.strip_prefix("https://github.com/")?; | ||
|
||
let mut parts = remaining.split('/'); | ||
let owner = parts.next()?; | ||
let name = parts.next()?; | ||
let subdir = if let Some("tree") = parts.next() { | ||
parts.last() | ||
} else { | ||
None | ||
}; | ||
|
||
Some(Self { | ||
owner, | ||
name, | ||
subdir, | ||
}) | ||
} | ||
|
||
fn build_readme_url(&self) -> String { | ||
let Self { | ||
owner, | ||
name, | ||
subdir, | ||
} = *self; | ||
|
||
match subdir { | ||
Some(subdir) if owner != "postgres" => { | ||
format!("https://api.github.com/repos/{owner}/{name}/readme/{subdir}") | ||
} | ||
_ => format!("https://api.github.com/repos/{owner}/{name}/readme"), | ||
} | ||
} | ||
} | ||
|
||
pub async fn fetch_and_save_readme( | ||
client: &GithubApiClient, | ||
registry: &Registry, | ||
extension_name: &str, | ||
) -> Result { | ||
let (extension_id, extension_url) = registry.get_repository_url(extension_name).await?; | ||
|
||
let url = extension_url.ok_or(ExtensionRegistryError::ResourceNotFound)?; | ||
|
||
let readme = client.fetch_readme(&url).await?; | ||
registry.upsert_readme(extension_id, &readme).await?; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::readme::GitHubProject; | ||
|
||
#[test] | ||
fn parses_github_urls() { | ||
let pgmq = "https://github.com/tembo-io/pgmq"; | ||
let auth_delay = "https://github.com/postgres/postgres/tree/master/contrib/auth_delay"; | ||
|
||
assert_eq!( | ||
GitHubProject::parse_url(pgmq).unwrap(), | ||
GitHubProject { | ||
owner: "tembo-io", | ||
name: "pgmq", | ||
subdir: None | ||
} | ||
); | ||
assert_eq!( | ||
GitHubProject::parse_url(auth_delay).unwrap(), | ||
GitHubProject { | ||
owner: "postgres", | ||
name: "postgres", | ||
subdir: Some("auth_delay") | ||
} | ||
); | ||
} | ||
|
||
#[test] | ||
fn builds_readme_urls() { | ||
let pgmq = "https://github.com/tembo-io/pgmq"; | ||
let auth_delay = "https://github.com/postgres/postgres/tree/master/contrib/auth_delay"; | ||
|
||
assert_eq!( | ||
GitHubProject::parse_url(pgmq).unwrap().build_readme_url(), | ||
"https://api.github.com/repos/tembo-io/pgmq/readme" | ||
); | ||
assert_eq!( | ||
GitHubProject::parse_url(auth_delay) | ||
.unwrap() | ||
.build_readme_url(), | ||
"https://api.github.com/repos/postgres/postgres/readme" | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use super::Registry; | ||
use crate::errors::Result; | ||
|
||
impl Registry { | ||
pub async fn get_extension_readme(&self, extension_name: &str) -> Result<String> { | ||
let record = sqlx::query!( | ||
"SELECT r.readme_html | ||
FROM readmes AS r | ||
JOIN extensions AS e ON r.extension_id = e.id | ||
WHERE e.name = $1", | ||
extension_name | ||
) | ||
.fetch_one(&self.pool) | ||
.await?; | ||
|
||
Ok(record.readme_html) | ||
} | ||
|
||
/// Fetch the repository of the extension with the given name | ||
pub async fn get_repository_url(&self, extension_name: &str) -> Result<(i64, Option<String>)> { | ||
let record = sqlx::query!( | ||
"SELECT id, repository FROM extensions WHERE extensions.name = $1", | ||
extension_name | ||
) | ||
.fetch_one(&self.pool) | ||
.await?; | ||
|
||
Ok((record.id, record.repository)) | ||
} | ||
|
||
pub async fn upsert_readme(&self, extension_id: i64, readme_html: &str) -> Result { | ||
sqlx::query!( | ||
"INSERT INTO readmes (extension_id, readme_html) | ||
VALUES ($1, $2) | ||
ON CONFLICT (extension_id) | ||
DO UPDATE SET readme_html = excluded.readme_html", | ||
extension_id as i32, | ||
readme_html | ||
) | ||
.execute(&self.pool) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
pub mod categories; | ||
pub mod download; | ||
pub mod extensions; | ||
pub mod readmes; | ||
pub mod root; | ||
pub mod token; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use crate::{errors::Result, readme::GithubApiClient, repository::Registry}; | ||
use actix_web::{get, post, web, HttpResponse}; | ||
|
||
#[post("/extensions/details/{extension_name}/readme")] | ||
pub async fn fetch_and_save_readme( | ||
path: web::Path<String>, | ||
registry: web::Data<Registry>, | ||
client: web::Data<GithubApiClient>, | ||
) -> Result<HttpResponse> { | ||
let extension_name = path.into_inner(); | ||
crate::readme::fetch_and_save_readme(client.as_ref(), registry.as_ref(), &extension_name) | ||
.await?; | ||
|
||
Ok(HttpResponse::Ok().finish()) | ||
} | ||
|
||
#[get("/extensions/details/{extension_name}/readme")] | ||
pub async fn get_readme( | ||
path: web::Path<String>, | ||
registry: web::Data<Registry>, | ||
) -> Result<HttpResponse> { | ||
let extension_name = path.into_inner(); | ||
let readme = registry.get_extension_readme(&extension_name).await?; | ||
|
||
Ok(HttpResponse::Ok().body(readme)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters