Compare commits

...
2 Commits
Author SHA1 Message Date
Christoph 2bd60f0e5b feat(git): enhance error reporting and auth robustness
The commit enhances Git operation reliability by improving how authentication errors are detected and displayed to the user. It standardizes Git output language across different locales and introduces a mechanism to summarize complex raw Git stderr messages, ensuring users receive clear feedback when cloning or interacting with repositories that fail due to credentials.

- Standardize git command output using LC_ALL=C for consistent English messaging.
- Implement error summarization logic to extract the most relevant message from raw Git stderr.
- Update credential dialogs to display summarized and improved authentication failure details.
2026-07-19 16:41:21 +02:00
Christoph 35310bec6d Update version to 2026.7.20 2026-07-13 00:27:15 +02:00
8 changed files with 38 additions and 9 deletions
+3 -1
View File
@@ -116,7 +116,9 @@
"Bash(cp /mnt/data/Development/GitLite/PKGBUILD .)",
"Bash(sed -i 's/^pkgrel=1/pkgrel=3/' PKGBUILD)",
"Bash(node -e \"const fs=require\\('fs'\\); const version='2026.8.1'; const pkgbuild=fs.readFileSync\\('PKGBUILD','utf8'\\).replace\\(/^pkgver=.*\\\\$/m, 'pkgver='+version\\).replace\\(/^pkgrel=.*\\\\$/m, 'pkgrel=1'\\); fs.writeFileSync\\('PKGBUILD', pkgbuild\\);\")",
"Bash(rm PKGBUILD)"
"Bash(rm PKGBUILD)",
"Bash(git -C /mnt/data/Development/GitLite stash)",
"Bash(git -C /mnt/data/Development/GitLite stash pop)"
]
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
# binary + desktop entry. Run `makepkg -si` from the repo root.
pkgname=gitty
pkgver=2026.7.19
pkgver=2026.7.20
pkgrel=1
pkgdesc="A lightweight, modern Git client built with Tauri"
arch=('x86_64')
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "gitty",
"version": "2026.7.19",
"version": "2026.7.20",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gitty",
"version": "2026.7.19",
"version": "2026.7.20",
"dependencies": {
"@lucide/svelte": "^1.21.0",
"@tailwindcss/vite": "^4.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitty",
"version": "2026.7.19",
"version": "2026.7.20",
"private": true,
"type": "module",
"scripts": {
+7
View File
@@ -300,6 +300,10 @@ static CANCELLABLE_GIT_OUTPUT_COUNTER: AtomicU64 = AtomicU64::new(0);
fn git_command() -> Command {
let mut command = Command::new("git");
// Force English output regardless of the system locale, so is_auth_error()
// and other message heuristics keep working (e.g. German git prints
// "Authentifizierung fehlgeschlagen" instead of "Authentication failed").
command.env("LC_ALL", "C");
#[cfg(windows)]
command.creation_flags(CREATE_NO_WINDOW);
command
@@ -4484,6 +4488,9 @@ fn is_auth_error(details: &str) -> bool {
|| d.contains(" 401")
|| d.contains("authorization failed")
|| d.contains("authentication required")
// Server-side message (e.g. Gitea/Forgejo: "remote: Failed to
// authenticate user"), independent of the local git locale.
|| d.contains("failed to authenticate")
}
// Windows' CreateProcess rejects command lines longer than ~32K chars with
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Gitty",
"version": "2026.7.19",
"version": "2026.7.20",
"identifier": "com.gitty",
"build": {
"beforeDevCommand": "npm run dev",
+9 -3
View File
@@ -144,6 +144,7 @@
isCredentialExpired,
isAuthError,
stripAuthPrefix,
summarizeGitError,
} from "./lib/credentials";
import { trackAnalyticsEvent, type AnalyticsEventProperties } from "./lib/analytics";
@@ -1997,7 +1998,10 @@
setCloneDialogError("");
if (fromStore) {
if (credentialKey) void credDelete(credentialKey).catch(() => {});
credDialogError = "Credentials were rejected or have expired. Please sign in again.";
const detail = summarizeGitError(message);
credDialogError = detail
? `${detail} — please sign in again.`
: "Credentials were rejected or have expired. Please sign in again.";
} else {
credDialogError = message || "Sign-in is required to clone this repository.";
}
@@ -2596,8 +2600,10 @@
if (fromStore) {
if (auth) {
if (key) void credDelete(key).catch(() => {});
credDialogError =
"Credentials were rejected or have expired. Please sign in again.";
const detail = summarizeGitError(message);
credDialogError = detail
? `${detail} — please sign in again.`
: "Credentials were rejected or have expired. Please sign in again.";
credDialogAction = action;
credDialogKey = key;
credDialogOpen = true;
+14
View File
@@ -55,3 +55,17 @@ export function stripAuthPrefix(message: string): string {
? message.slice(AUTH_PREFIX.length).trim()
: message;
}
/**
* Condenses raw git stderr to the single most relevant line for the
* credential dialog. Prefers the server's own explanation ("remote: ...")
* over git's generic wrapper ("fatal: Authentication failed for ...").
*/
export function summarizeGitError(message: string): string {
const lines = message
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
const remote = lines.find((line) => line.toLowerCase().startsWith("remote:"));
return remote ?? lines[0] ?? "";
}