Resolve connected library branch fallbacks
Some checks failed
Codex Template Compliance / template-compliance (push) Successful in 7s
Build / build-windows (push) Has been cancelled

This commit is contained in:
MrSphay
2026-05-15 22:51:53 +02:00
parent cbaaa09998
commit f3685cace3
2 changed files with 68 additions and 24 deletions

View File

@@ -9,3 +9,4 @@ All notable Modrinth Plus changes are documented here.
- Added Windows installer publishing to the Gitea generic package registry.
- Added Codex repository context and release/security documentation.
- Fixed startup compatibility with existing official Modrinth App databases that recorded different checksums for historical SQLite migrations.
- Fixed Connected Library Git repository URL resolution for repositories that use `master` instead of `main`.

View File

@@ -157,9 +157,7 @@ pub async fn list() -> crate::Result<Vec<ConnectedPack>> {
pub async fn connect(source_url: String) -> crate::Result<ConnectedPack> {
let state = State::get().await?;
let manifest_url = normalize_manifest_url(&source_url)?;
let manifest = fetch_manifest(&manifest_url).await?;
validate_manifest(&manifest)?;
let (manifest_url, manifest) = resolve_manifest(&source_url).await?;
upsert_manifest(&state.pool, None, &source_url, &manifest_url, &manifest)
.await?;
get_by_source(&state.pool, &source_url).await
@@ -197,14 +195,17 @@ pub async fn set_auto_update(
pub async fn check(id: String) -> crate::Result<ConnectedCheckResult> {
let state = State::get().await?;
let pack = get_by_id(&state.pool, &id).await?;
let manifest = fetch_manifest(&pack.manifest_url).await?;
validate_manifest(&manifest)?;
let (manifest_url, manifest) = match fetch_manifest(&pack.manifest_url).await
{
Ok(manifest) => (pack.manifest_url.clone(), manifest),
Err(_) => resolve_manifest(&pack.source_url).await?,
};
upsert_manifest(
&state.pool,
Some(&pack.id),
&pack.source_url,
&pack.manifest_url,
&manifest_url,
&manifest,
)
.await?;
@@ -306,7 +307,7 @@ pub async fn install(id: String) -> crate::Result<ConnectedPack> {
get_by_id(&state.pool, &id).await
}
fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
fn manifest_url_candidates(source_url: &str) -> crate::Result<Vec<String>> {
let source = source_url.trim();
let parsed = Url::parse(source)?;
@@ -318,7 +319,7 @@ fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
}
if source.ends_with(MANIFEST_FILE_NAME) || source.contains("/raw/") {
return Ok(source.to_string());
return Ok(vec![source.to_string()]);
}
let host = parsed.host_str().unwrap_or_default();
@@ -329,30 +330,52 @@ fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
if host == "github.com" && segments.len() >= 2 {
let repo = segments[1].trim_end_matches(".git");
return Ok(format!(
"https://raw.githubusercontent.com/{}/{}/main/{}",
segments[0], repo, MANIFEST_FILE_NAME
));
return Ok(vec![
format!(
"https://raw.githubusercontent.com/{}/{}/main/{}",
segments[0], repo, MANIFEST_FILE_NAME
),
format!(
"https://raw.githubusercontent.com/{}/{}/master/{}",
segments[0], repo, MANIFEST_FILE_NAME
),
]);
}
if host == "gitlab.com" && segments.len() >= 2 {
let repo = segments[1].trim_end_matches(".git");
return Ok(format!(
"https://gitlab.com/{}/{}/-/raw/main/{}",
segments[0], repo, MANIFEST_FILE_NAME
));
return Ok(vec![
format!(
"https://gitlab.com/{}/{}/-/raw/main/{}",
segments[0], repo, MANIFEST_FILE_NAME
),
format!(
"https://gitlab.com/{}/{}/-/raw/master/{}",
segments[0], repo, MANIFEST_FILE_NAME
),
]);
}
if segments.len() >= 2 {
let repo = segments[1].trim_end_matches(".git");
return Ok(format!(
"{}://{}/{}/{}/raw/branch/main/{}",
parsed.scheme(),
host,
segments[0],
repo,
MANIFEST_FILE_NAME
));
return Ok(vec![
format!(
"{}://{}/{}/{}/raw/branch/main/{}",
parsed.scheme(),
host,
segments[0],
repo,
MANIFEST_FILE_NAME
),
format!(
"{}://{}/{}/{}/raw/branch/master/{}",
parsed.scheme(),
host,
segments[0],
repo,
MANIFEST_FILE_NAME
),
]);
}
Err(ErrorKind::InputError(
@@ -362,6 +385,26 @@ fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
.into())
}
async fn resolve_manifest(
source_url: &str,
) -> crate::Result<(String, ConnectedManifest)> {
let candidates = manifest_url_candidates(source_url)?;
let mut errors = Vec::new();
for manifest_url in candidates {
match fetch_manifest(&manifest_url).await {
Ok(manifest) => return Ok((manifest_url, manifest)),
Err(err) => errors.push(format!("{manifest_url}: {err}")),
}
}
Err(ErrorKind::InputError(format!(
"Could not fetch {MANIFEST_FILE_NAME}. Tried: {}",
errors.join("; ")
))
.into())
}
async fn fetch_manifest(url: &str) -> crate::Result<ConnectedManifest> {
let manifest = reqwest::get(url)
.await?