Compare commits
11
Commits
14a1c4944a
...
v1.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0840f93d0d
|
||
|
|
42829ce0a0
|
||
|
|
bc3f4c4ec6
|
||
|
|
c3d5ed8b26
|
||
|
|
a7c0c25b26
|
||
|
|
08cca0ca51
|
||
|
|
2f61e15646
|
||
|
|
5e5e3f5b17
|
||
|
|
f04c9611b6
|
||
|
|
f4160df1d7
|
||
|
|
3f5f18d98f
|
Generated
+1
-1
@@ -866,7 +866,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mirror-package"
|
name = "mirror-package"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "mirror-package"
|
name = "mirror-package"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ['DragonSlayer_14']
|
authors = ['DragonSlayer_14']
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
+38
-26
@@ -1,6 +1,6 @@
|
|||||||
|
use crate::utils::{clean_repo_input, sanitize_string};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::utils::sanitize_env_vars;
|
|
||||||
|
|
||||||
fn default_true() -> bool {
|
fn default_true() -> bool {
|
||||||
true
|
true
|
||||||
@@ -22,7 +22,7 @@ pub struct RepoConfig {
|
|||||||
impl RepoConfig {
|
impl RepoConfig {
|
||||||
pub fn new(name: impl Into<String>, include_prereleases: bool) -> Self {
|
pub fn new(name: impl Into<String>, include_prereleases: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: AppConfig::normalize_repo_name(&name.into()),
|
||||||
include_prereleases,
|
include_prereleases,
|
||||||
last_synced_tag: None,
|
last_synced_tag: None,
|
||||||
}
|
}
|
||||||
@@ -50,21 +50,17 @@ pub struct AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AppConfig {
|
impl AppConfig {
|
||||||
/// Normalisiert die Repository-Eingabe, indem führende/nachgestellte Schrägstriche und GitHub-URL-Präfixe entfernt werden.
|
/// Normalisiert die Repository-Eingabe, indem führende/nachgestellte Schrägstriche,
|
||||||
|
/// Query-Parameter, Fragmente und GitHub-URL-Präfixe entfernt werden.
|
||||||
pub fn normalize_repo_name(input: &str) -> String {
|
pub fn normalize_repo_name(input: &str) -> String {
|
||||||
let trimmed = input.trim();
|
clean_repo_input(input).to_string()
|
||||||
let cleaned = trimmed
|
|
||||||
.trim_start_matches("https://github.com/")
|
|
||||||
.trim_start_matches("http://github.com/")
|
|
||||||
.trim_start_matches("github.com/")
|
|
||||||
.trim_end_matches(".git")
|
|
||||||
.trim_matches('/');
|
|
||||||
cleaned.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fügt ein Repository zur Konfiguration hinzu oder aktualisiert ein bestehendes.
|
/// Fügt ein Repository zur Konfiguration hinzu oder aktualisiert ein bestehendes.
|
||||||
pub fn add_or_update_repo(&mut self, repo: RepoConfig) {
|
pub fn add_or_update_repo(&mut self, mut repo: RepoConfig) {
|
||||||
if let Some(existing) = self.repositories.iter_mut().find(|r| r.name.eq_ignore_ascii_case(&repo.name)) {
|
repo.name = Self::normalize_repo_name(&repo.name);
|
||||||
|
if let Some(existing) = self.repositories.iter_mut().find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&repo.name)) {
|
||||||
|
existing.name = repo.name;
|
||||||
existing.include_prereleases = repo.include_prereleases;
|
existing.include_prereleases = repo.include_prereleases;
|
||||||
} else {
|
} else {
|
||||||
self.repositories.push(repo);
|
self.repositories.push(repo);
|
||||||
@@ -75,20 +71,20 @@ impl AppConfig {
|
|||||||
pub fn remove_repo(&mut self, repo_name: &str) -> bool {
|
pub fn remove_repo(&mut self, repo_name: &str) -> bool {
|
||||||
let normalized = Self::normalize_repo_name(repo_name);
|
let normalized = Self::normalize_repo_name(repo_name);
|
||||||
let before_len = self.repositories.len();
|
let before_len = self.repositories.len();
|
||||||
self.repositories.retain(|r| !r.name.eq_ignore_ascii_case(&normalized));
|
self.repositories.retain(|r| !Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized));
|
||||||
self.repositories.len() < before_len
|
self.repositories.len() < before_len
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sucht ein Repository anhand des Namens.
|
/// Sucht ein Repository anhand des Namens.
|
||||||
pub fn find_repo(&self, repo_name: &str) -> Option<&RepoConfig> {
|
pub fn find_repo(&self, repo_name: &str) -> Option<&RepoConfig> {
|
||||||
let normalized = Self::normalize_repo_name(repo_name);
|
let normalized = Self::normalize_repo_name(repo_name);
|
||||||
self.repositories.iter().find(|r| r.name.eq_ignore_ascii_case(&normalized))
|
self.repositories.iter().find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Aktualisiert den zuletzt synchronisierten Tag für ein bestimmtes Repository.
|
/// Aktualisiert den zuletzt synchronisierten Tag für ein bestimmtes Repository.
|
||||||
pub fn update_last_synced_tag(&mut self, repo_name: &str, tag: String) {
|
pub fn update_last_synced_tag(&mut self, repo_name: &str, tag: String) {
|
||||||
let normalized = Self::normalize_repo_name(repo_name);
|
let normalized = Self::normalize_repo_name(repo_name);
|
||||||
if let Some(repo) = self.repositories.iter_mut().find(|r| r.name.eq_ignore_ascii_case(&normalized)) {
|
if let Some(repo) = self.repositories.iter_mut().find(|r| Self::normalize_repo_name(&r.name).eq_ignore_ascii_case(&normalized)) {
|
||||||
repo.last_synced_tag = Some(tag);
|
repo.last_synced_tag = Some(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,20 +106,36 @@ pub fn get_config_file_path() -> PathBuf {
|
|||||||
/// Lädt die Anwendungskonfiguration. Verwendet Standardwerte, falls keine Datei vorhanden ist.
|
/// Lädt die Anwendungskonfiguration. Verwendet Standardwerte, falls keine Datei vorhanden ist.
|
||||||
pub fn load_config() -> AppConfig {
|
pub fn load_config() -> AppConfig {
|
||||||
let mut config = config_ctdra::load_config::<AppConfig>();
|
let mut config = config_ctdra::load_config::<AppConfig>();
|
||||||
let mut env_vars = std::env::vars().collect();
|
|
||||||
sanitize_env_vars(&mut env_vars);
|
for repo in &mut config.repositories {
|
||||||
if let Some(gitea_url) = env_vars.get("GITEA_URL") {
|
repo.name = AppConfig::normalize_repo_name(&repo.name);
|
||||||
config.gitea_url = Some(gitea_url.clone());
|
|
||||||
}
|
}
|
||||||
if let Some(gitea_token) = env_vars.get("GITEA_TOKEN") {
|
|
||||||
config.gitea_token = Some(gitea_token.clone());
|
if let Ok(val) = std::env::var("GITEA_URL") {
|
||||||
|
let val = sanitize_string(&val);
|
||||||
|
if !val.is_empty() {
|
||||||
|
config.gitea_url = Some(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(registry_owner) = env_vars.get("REGISTRY_OWNER") {
|
if let Ok(val) = std::env::var("GITEA_TOKEN") {
|
||||||
config.registry_owner = Some(registry_owner.clone());
|
let val = sanitize_string(&val);
|
||||||
|
if !val.is_empty() {
|
||||||
|
config.gitea_token = Some(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(github_token) = env_vars.get("GITHUB_TOKEN") {
|
if let Ok(val) = std::env::var("REGISTRY_OWNER") {
|
||||||
config.github_token = Some(github_token.clone());
|
let val = sanitize_string(&val);
|
||||||
|
if !val.is_empty() {
|
||||||
|
config.registry_owner = Some(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if let Ok(val) = std::env::var("GITHUB_TOKEN") {
|
||||||
|
let val = sanitize_string(&val);
|
||||||
|
if !val.is_empty() {
|
||||||
|
config.github_token = Some(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-14
@@ -81,12 +81,13 @@ struct GhApiAsset {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GitHubClient {
|
pub struct GitHubClient {
|
||||||
client: reqwest::Client,
|
client: reqwest::Client,
|
||||||
pub token: Option<String>,
|
token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GitHubClient {
|
impl GitHubClient {
|
||||||
/// Erstellt einen neuen GitHub-API-Client mit optionalem Authentifizierungstoken.
|
/// Erstellt einen neuen GitHub-API-Client mit optionalem Authentifizierungstoken.
|
||||||
pub fn new(token: Option<String>) -> Result<Self> {
|
pub fn new(token: Option<String>) -> Result<Self> {
|
||||||
|
let token = token.filter(|t| !t.trim().is_empty());
|
||||||
let mut headers = reqwest::header::HeaderMap::new();
|
let mut headers = reqwest::header::HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(
|
||||||
reqwest::header::USER_AGENT,
|
reqwest::header::USER_AGENT,
|
||||||
@@ -105,6 +106,11 @@ impl GitHubClient {
|
|||||||
Ok(Self { client, token })
|
Ok(Self { client, token })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gibt das optionale Authentifizierungstoken zurück (falls gesetzt).
|
||||||
|
pub fn token(&self) -> Option<&str> {
|
||||||
|
self.token.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Ruft Releases für ein angegebenes Repository ab (Format "owner/repo").
|
/// Ruft Releases für ein angegebenes Repository ab (Format "owner/repo").
|
||||||
///
|
///
|
||||||
@@ -130,9 +136,7 @@ impl GitHubClient {
|
|||||||
|
|
||||||
let mut req = self.client.get(&url);
|
let mut req = self.client.get(&url);
|
||||||
if let Some(token) = &self.token {
|
if let Some(token) = &self.token {
|
||||||
if !token.is_empty() {
|
req = req.bearer_auth(token);
|
||||||
req = req.bearer_auth(token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let resp = req.send().await.with_context(|| format!("Failed to send request to {}", url))?;
|
let resp = req.send().await.with_context(|| format!("Failed to send request to {}", url))?;
|
||||||
@@ -220,9 +224,7 @@ impl GitHubClient {
|
|||||||
pub async fn download_asset_stream(&self, download_url: &str) -> Result<reqwest::Response> {
|
pub async fn download_asset_stream(&self, download_url: &str) -> Result<reqwest::Response> {
|
||||||
let mut req = self.client.get(download_url);
|
let mut req = self.client.get(download_url);
|
||||||
if let Some(token) = &self.token {
|
if let Some(token) = &self.token {
|
||||||
if !token.is_empty() {
|
req = req.bearer_auth(token);
|
||||||
req = req.bearer_auth(token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let resp = req
|
let resp = req
|
||||||
@@ -244,13 +246,7 @@ impl GitHubClient {
|
|||||||
|
|
||||||
/// Hilfsfunktion zum Parsen von "owner/repo" aus einer Repository-Zeichenkette.
|
/// Hilfsfunktion zum Parsen von "owner/repo" aus einer Repository-Zeichenkette.
|
||||||
pub fn parse_repo_owner_name(repo: &str) -> Result<(&str, &str)> {
|
pub fn parse_repo_owner_name(repo: &str) -> Result<(&str, &str)> {
|
||||||
let cleaned = repo
|
let cleaned = crate::utils::clean_repo_input(repo);
|
||||||
.trim()
|
|
||||||
.trim_start_matches("https://github.com/")
|
|
||||||
.trim_start_matches("http://github.com/")
|
|
||||||
.trim_start_matches("github.com/")
|
|
||||||
.trim_end_matches(".git")
|
|
||||||
.trim_matches('/');
|
|
||||||
|
|
||||||
let parts: Vec<&str> = cleaned.split('/').collect();
|
let parts: Vec<&str> = cleaned.split('/').collect();
|
||||||
if parts.len() != 2 || parts[0].is_empty() || parts[1].is_empty() {
|
if parts.len() != 2 || parts[0].is_empty() || parts[1].is_empty() {
|
||||||
|
|||||||
+37
-4
@@ -10,10 +10,10 @@
|
|||||||
/// The sanitized string with surrounding quotes removed.
|
/// The sanitized string with surrounding quotes removed.
|
||||||
pub fn sanitize_string(input: &str) -> String {
|
pub fn sanitize_string(input: &str) -> String {
|
||||||
let trimmed = input.trim();
|
let trimmed = input.trim();
|
||||||
if trimmed.starts_with('"') && trimmed.ends_with('"') {
|
if let Some(stripped) = trimmed.strip_prefix('"').and_then(|s| s.strip_suffix('"')) {
|
||||||
trimmed[1..trimmed.len() - 1].to_string()
|
stripped.to_string()
|
||||||
} else if trimmed.starts_with('') && trimmed.ends_with('') {
|
} else if let Some(stripped) = trimmed.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) {
|
||||||
trimmed[1..trimmed.len() - 1].to_string()
|
stripped.to_string()
|
||||||
} else {
|
} else {
|
||||||
trimmed.to_string()
|
trimmed.to_string()
|
||||||
}
|
}
|
||||||
@@ -29,3 +29,36 @@ pub fn sanitize_env_vars(env_vars: &mut std::collections::HashMap<String, String
|
|||||||
*value = sanitize_string(value);
|
*value = sanitize_string(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bereinigt eine Repository-Eingabe (URL oder Kurzform), indem Query-Parameter, Fragmente,
|
||||||
|
/// URL-Schemata/Hosts (`github.com`, `www.github.com`, `git@github.com:`), `.git`-Endungen
|
||||||
|
/// und umgebende Schrägstriche entfernt werden.
|
||||||
|
pub fn clean_repo_input(input: &str) -> &str {
|
||||||
|
let mut trimmed = input.trim();
|
||||||
|
if (trimmed.starts_with('"') && trimmed.ends_with('"'))
|
||||||
|
|| (trimmed.starts_with('\'') && trimmed.ends_with('\''))
|
||||||
|
{
|
||||||
|
if trimmed.len() >= 2 {
|
||||||
|
trimmed = trimmed[1..trimmed.len() - 1].trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let without_query_or_fragment = match trimmed.find(|c| c == '?' || c == '#') {
|
||||||
|
Some(idx) => &trimmed[..idx],
|
||||||
|
None => trimmed,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cleaned = without_query_or_fragment
|
||||||
|
.trim_start_matches("git@github.com:")
|
||||||
|
.trim_start_matches("https://")
|
||||||
|
.trim_start_matches("http://")
|
||||||
|
.trim_start_matches("www.github.com/")
|
||||||
|
.trim_start_matches("github.com/")
|
||||||
|
.trim_matches('/');
|
||||||
|
|
||||||
|
if let Some(stripped) = cleaned.strip_suffix(".git") {
|
||||||
|
cleaned = stripped.trim_matches('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned
|
||||||
|
}
|
||||||
|
|||||||
+77
-6
@@ -1,5 +1,5 @@
|
|||||||
use mirror_package::config::{load_config, AppConfig, RepoConfig};
|
use mirror_package::config::{AppConfig, RepoConfig, load_config};
|
||||||
use mirror_package::utils::{sanitize_env_vars, sanitize_string};
|
use mirror_package::utils::{clean_repo_input, sanitize_env_vars, sanitize_string};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -41,12 +41,66 @@ fn test_load_config_with_env_vars() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_sanitize_string() {
|
fn test_sanitize_string() {
|
||||||
assert_eq!(sanitize_string("\"https://gitea.example.com\""), "https://gitea.example.com");
|
assert_eq!(sanitize_string("\"https://gitea.example.com\""), "https://gitea.example.com");
|
||||||
|
assert_eq!(sanitize_string("'https://gitea.example.com'"), "https://gitea.example.com");
|
||||||
assert_eq!(sanitize_string("\"token123\""), "token123");
|
assert_eq!(sanitize_string("\"token123\""), "token123");
|
||||||
|
assert_eq!(sanitize_string("'token123'"), "token123");
|
||||||
assert_eq!(sanitize_string("\"owner\""), "owner");
|
assert_eq!(sanitize_string("\"owner\""), "owner");
|
||||||
|
assert_eq!(sanitize_string("'owner'"), "owner");
|
||||||
assert_eq!(sanitize_string("\"github_token123\""), "github_token123");
|
assert_eq!(sanitize_string("\"github_token123\""), "github_token123");
|
||||||
|
assert_eq!(sanitize_string("'github_token123'"), "github_token123");
|
||||||
assert_eq!(sanitize_string("no_quotes"), "no_quotes");
|
assert_eq!(sanitize_string("no_quotes"), "no_quotes");
|
||||||
assert_eq!(sanitize_string("\"single_quote\""), "single_quote");
|
assert_eq!(sanitize_string("\"single_quote\""), "single_quote");
|
||||||
|
assert_eq!(sanitize_string("'single_quote'"), "single_quote");
|
||||||
assert_eq!(sanitize_string("\"escaped_quote\""), "escaped_quote");
|
assert_eq!(sanitize_string("\"escaped_quote\""), "escaped_quote");
|
||||||
|
// Edge cases: single character inputs
|
||||||
|
assert_eq!(sanitize_string("\""), "\"");
|
||||||
|
assert_eq!(sanitize_string("'"), "'");
|
||||||
|
assert_eq!(sanitize_string("a"), "a");
|
||||||
|
// Edge cases: empty quotes and empty strings
|
||||||
|
assert_eq!(sanitize_string("\"\""), "");
|
||||||
|
assert_eq!(sanitize_string("''"), "");
|
||||||
|
assert_eq!(sanitize_string(""), "");
|
||||||
|
assert_eq!(sanitize_string(" "), "");
|
||||||
|
assert_eq!(sanitize_string(" 'hello' "), "hello");
|
||||||
|
assert_eq!(sanitize_string(" \"world\" "), "world");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clean_repo_input() {
|
||||||
|
assert_eq!(clean_repo_input("owner/repo"), "owner/repo");
|
||||||
|
assert_eq!(clean_repo_input("https://github.com/owner/repo"), "owner/repo");
|
||||||
|
assert_eq!(clean_repo_input("http://github.com/owner/repo"), "owner/repo");
|
||||||
|
assert_eq!(clean_repo_input("github.com/owner/repo"), "owner/repo");
|
||||||
|
assert_eq!(clean_repo_input("https://github.com/owner/repo.git"), "owner/repo");
|
||||||
|
assert_eq!(clean_repo_input("https://github.com/owner/repo/"), "owner/repo");
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file"),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("https://github.com/raspberrypi/rpi-imager/?tab=readme-ov-file"),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("https://github.com/raspberrypi/rpi-imager.git?tab=readme-ov-file"),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("https://github.com/raspberrypi/rpi-imager#readme"),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file#install"),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("raspberrypi/rpi-imager?tab=readme-ov-file"),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
clean_repo_input("\"https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file\""),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -54,15 +108,29 @@ fn test_normalize_repo_name() {
|
|||||||
let input = "https://github.com/owner/repo.git";
|
let input = "https://github.com/owner/repo.git";
|
||||||
let normalized = AppConfig::normalize_repo_name(input);
|
let normalized = AppConfig::normalize_repo_name(input);
|
||||||
assert_eq!(normalized, "owner/repo");
|
assert_eq!(normalized, "owner/repo");
|
||||||
|
|
||||||
|
let input_with_query = "https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file";
|
||||||
|
assert_eq!(
|
||||||
|
AppConfig::normalize_repo_name(input_with_query),
|
||||||
|
"raspberrypi/rpi-imager"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_or_update_repo() {
|
fn test_add_or_update_repo() {
|
||||||
let mut config = AppConfig::default();
|
let mut config = AppConfig::default();
|
||||||
let repo = RepoConfig::new("owner/repo", true);
|
let repo = RepoConfig::new("https://github.com/owner/repo?tab=readme-ov-file", true);
|
||||||
config.add_or_update_repo(repo.clone());
|
config.add_or_update_repo(repo.clone());
|
||||||
assert_eq!(config.repositories.len(), 1);
|
assert_eq!(config.repositories.len(), 1);
|
||||||
assert_eq!(config.repositories[0], repo);
|
assert_eq!(config.repositories[0].name, "owner/repo");
|
||||||
|
assert_eq!(config.repositories[0].include_prereleases, true);
|
||||||
|
|
||||||
|
// Updating existing repo with a URL with query param
|
||||||
|
let repo_updated = RepoConfig::new("https://github.com/owner/repo#readme", false);
|
||||||
|
config.add_or_update_repo(repo_updated);
|
||||||
|
assert_eq!(config.repositories.len(), 1);
|
||||||
|
assert_eq!(config.repositories[0].name, "owner/repo");
|
||||||
|
assert_eq!(config.repositories[0].include_prereleases, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -70,7 +138,7 @@ fn test_remove_repo() {
|
|||||||
let mut config = AppConfig::default();
|
let mut config = AppConfig::default();
|
||||||
let repo = RepoConfig::new("owner/repo", true);
|
let repo = RepoConfig::new("owner/repo", true);
|
||||||
config.add_or_update_repo(repo.clone());
|
config.add_or_update_repo(repo.clone());
|
||||||
assert!(config.remove_repo("owner/repo"));
|
assert!(config.remove_repo("https://github.com/owner/repo?tab=readme-ov-file"));
|
||||||
assert!(config.repositories.is_empty());
|
assert!(config.repositories.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +147,10 @@ fn test_find_repo() {
|
|||||||
let mut config = AppConfig::default();
|
let mut config = AppConfig::default();
|
||||||
let repo = RepoConfig::new("owner/repo", true);
|
let repo = RepoConfig::new("owner/repo", true);
|
||||||
config.add_or_update_repo(repo.clone());
|
config.add_or_update_repo(repo.clone());
|
||||||
assert_eq!(config.find_repo("owner/repo"), Some(&repo));
|
assert_eq!(
|
||||||
|
config.find_repo("https://github.com/owner/repo?tab=readme-ov-file"),
|
||||||
|
Some(&RepoConfig::new("owner/repo", true))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+18
-5
@@ -64,6 +64,18 @@ fn test_parse_repo_owner_name() {
|
|||||||
parse_repo_owner_name("https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher.git").unwrap(),
|
parse_repo_owner_name("https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher.git").unwrap(),
|
||||||
("Heroic-Games-Launcher", "HeroicGamesLauncher")
|
("Heroic-Games-Launcher", "HeroicGamesLauncher")
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_repo_owner_name("https://github.com/raspberrypi/rpi-imager?tab=readme-ov-file").unwrap(),
|
||||||
|
("raspberrypi", "rpi-imager")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_repo_owner_name("https://github.com/raspberrypi/rpi-imager/?tab=readme-ov-file#install").unwrap(),
|
||||||
|
("raspberrypi", "rpi-imager")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_repo_owner_name("raspberrypi/rpi-imager?tab=readme-ov-file").unwrap(),
|
||||||
|
("raspberrypi", "rpi-imager")
|
||||||
|
);
|
||||||
|
|
||||||
assert!(parse_repo_owner_name("invalid_repo").is_err());
|
assert!(parse_repo_owner_name("invalid_repo").is_err());
|
||||||
assert!(parse_repo_owner_name("invalid/repo/extra").is_err());
|
assert!(parse_repo_owner_name("invalid/repo/extra").is_err());
|
||||||
@@ -73,17 +85,18 @@ fn test_parse_repo_owner_name() {
|
|||||||
async fn test_github_client_empty_token() {
|
async fn test_github_client_empty_token() {
|
||||||
use mirror_package::github::GitHubClient;
|
use mirror_package::github::GitHubClient;
|
||||||
|
|
||||||
// Test that a client with an empty token can be created
|
// Test that a client with an empty or whitespace token sanitizes it to None
|
||||||
let client = GitHubClient::new(Some("".to_string())).expect("Failed to create client with empty token");
|
let client = GitHubClient::new(Some("".to_string())).expect("Failed to create client with empty token");
|
||||||
|
assert_eq!(client.token(), None);
|
||||||
|
|
||||||
// The client should be created successfully but has_auth() should return false
|
let client_whitespace = GitHubClient::new(Some(" ".to_string())).expect("Failed to create client with whitespace token");
|
||||||
assert!(client.token.is_none() || client.token.as_ref().map_or(true, |t| t.is_empty()));
|
assert_eq!(client_whitespace.token(), None);
|
||||||
|
|
||||||
// Test with a valid token
|
// Test with a valid token
|
||||||
let client_with_token = GitHubClient::new(Some("valid_token".to_string())).expect("Failed to create client with valid token");
|
let client_with_token = GitHubClient::new(Some("valid_token".to_string())).expect("Failed to create client with valid token");
|
||||||
assert!(client_with_token.token.as_ref().map_or(false, |t| !t.is_empty()));
|
assert_eq!(client_with_token.token(), Some("valid_token"));
|
||||||
|
|
||||||
// Test with no token
|
// Test with no token
|
||||||
let client_no_token = GitHubClient::new(None).expect("Failed to create client with no token");
|
let client_no_token = GitHubClient::new(None).expect("Failed to create client with no token");
|
||||||
assert!(client_no_token.token.is_none());
|
assert_eq!(client_no_token.token(), None);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user