feat(integrations): add Git hosting integrations and repo listing

Add support for integrating with external Git hosts (GitLab, Gitea,
and Azure DevOps). The backend gains a client to fetch paginated
repository lists, normalise base URLs, and surface provider errors.
Credentials are loaded from the OS keychain and a Tauri command is
exposed for the frontend to list integration repositories.

- Implement integration client with pagination, deserialization,
  and provider-specific handling.
- Centralise keychain credential loading and expose listing command.
- Update UI to manage integration metadata, persist settings, and
  save/remove tokens to the OS keychain for cloning and operations.
This commit is contained in:
2026-08-29 23:25:51 +02:00
parent 823a50ce85
commit 91263547db
10 changed files with 1190 additions and 130 deletions
+12 -10
View File
@@ -2878,6 +2878,17 @@ fn cred_entry(key: &str) -> Result<keyring::Entry, String> {
keyring::Entry::new(CRED_SERVICE, key).map_err(|err| format!("Keychain unavailable: {err}"))
}
pub(crate) fn load_stored_credential(key: &str) -> Result<Option<StoredCredential>, String> {
let entry = cred_entry(key)?;
match entry.get_password() {
Ok(json) => serde_json::from_str::<StoredCredential>(&json)
.map(Some)
.map_err(|err| format!("Stored credentials unreadable: {err}")),
Err(keyring::Error::NoEntry) => Ok(None),
Err(err) => Err(format!("Keychain access failed: {err}")),
}
}
/// Returns the remote URL used for auth key derivation (upstream remote of the
/// current branch, falling back to `origin`, then the first configured remote).
#[tauri::command(async)]
@@ -3061,16 +3072,7 @@ fn push_args_for_repo_to(
#[tauri::command(async)]
pub fn cred_load(key: String) -> Result<Option<StoredCredential>, String> {
let entry = cred_entry(&key)?;
match entry.get_password() {
Ok(json) => {
let cred = serde_json::from_str::<StoredCredential>(&json)
.map_err(|err| format!("Stored credentials unreadable: {err}"))?;
Ok(Some(cred))
}
Err(keyring::Error::NoEntry) => Ok(None),
Err(err) => Err(format!("Keychain access failed: {err}")),
}
load_stored_credential(&key)
}
#[tauri::command(async)]