added the provider trait, github provider, and a fzf selector.

i forgot to commit :(
This commit is contained in:
2026-07-10 18:53:36 -05:00
parent b476cd1e85
commit 0e2155c1b3
6 changed files with 3818 additions and 3 deletions
+85
View File
@@ -0,0 +1,85 @@
use super::Repository;
use serde::Deserialize;
use crate::providers::Provider;
// TODO: add email and password authentication for viewing private repos.
pub struct Github {
pub username: String,
}
// 1. This struct matches GitHub's exact API shape.
// It remains completely hidden inside your GitHub provider module.
#[derive(Deserialize, Debug)]
struct GithubRepoDto {
id: u64,
name: String,
owner: GithubOwnerDto,
ssh_url: Option<String>,
clone_url: String, // Or html_url
stargazers_count: u64,
description: Option<String>,
}
#[derive(Deserialize, Debug)]
struct GithubOwnerDto {
login: String,
}
// 2. Map the GitHub DTO to your general Repository struct
impl From<GithubRepoDto> for Repository {
fn from(gh: GithubRepoDto) -> Self {
Repository {
id: gh.id,
name: gh.name,
owner: gh.owner.login,
ssh_url: gh.ssh_url,
https_url: gh.clone_url,
stars: gh.stargazers_count,
description: gh.description,
}
}
}
impl Provider for Github {
async fn repositories(&self) -> super::Result<Vec<Repository>> {
let client = reqwest::Client::new();
let mut page = 1;
let mut repos: Vec<Repository> = Vec::new();
loop {
let url = format!(
"https://api.github.com/users/{}/repos?per_page=100&page={}",
&self.username, page
);
let response = client
.get(&url)
.header("User-Agent", "my-app")
.send()
.await?;
let status = response.status();
if !status.is_success() {
let error_text = response.text().await?;
let err = format!("Github API Error ({}): {}", status, error_text);
return Err(err.into());
}
let gh_page: Vec<GithubRepoDto> = response.json().await?;
if gh_page.is_empty() {
break;
}
// Convert the GitHub DTOs seamlessly into your clean domain structs
let domain_repos = gh_page.into_iter().map(Repository::from);
repos.extend(domain_repos);
page += 1;
}
Ok(repos)
}
}