Decouple git from github errors (#1347)
* Decouple git from github errors
* Fix git error display (vibe-kanban 7352dadc)
After the last few commits git cli not logged in error does not get displayed to the user. Network tab shows this:
{
"success": false,
"data": null,
"error_data": {
"type": "git_cli_not_logged_in"
},
"message": null
}
This commit is contained in:
@@ -93,7 +93,6 @@ fn generate_types_content() -> String {
|
|||||||
server::routes::tasks::CreateAndStartTaskRequest::decl(),
|
server::routes::tasks::CreateAndStartTaskRequest::decl(),
|
||||||
server::routes::task_attempts::CreateGitHubPrRequest::decl(),
|
server::routes::task_attempts::CreateGitHubPrRequest::decl(),
|
||||||
server::routes::images::ImageResponse::decl(),
|
server::routes::images::ImageResponse::decl(),
|
||||||
services::services::github::GitHubServiceError::decl(),
|
|
||||||
services::services::config::Config::decl(),
|
services::services::config::Config::decl(),
|
||||||
services::services::config::NotificationConfig::decl(),
|
services::services::config::NotificationConfig::decl(),
|
||||||
services::services::config::ThemeMode::decl(),
|
services::services::config::ThemeMode::decl(),
|
||||||
@@ -138,6 +137,7 @@ fn generate_types_content() -> String {
|
|||||||
server::routes::task_attempts::gh_cli_setup::GhCliSetupError::decl(),
|
server::routes::task_attempts::gh_cli_setup::GhCliSetupError::decl(),
|
||||||
server::routes::task_attempts::RebaseTaskAttemptRequest::decl(),
|
server::routes::task_attempts::RebaseTaskAttemptRequest::decl(),
|
||||||
server::routes::task_attempts::GitOperationError::decl(),
|
server::routes::task_attempts::GitOperationError::decl(),
|
||||||
|
server::routes::task_attempts::CreatePrError::decl(),
|
||||||
server::routes::task_attempts::CommitInfo::decl(),
|
server::routes::task_attempts::CommitInfo::decl(),
|
||||||
server::routes::task_attempts::BranchStatus::decl(),
|
server::routes::task_attempts::BranchStatus::decl(),
|
||||||
services::services::git::ConflictOp::decl(),
|
services::services::git::ConflictOp::decl(),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ use git2::BranchType;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use services::services::{
|
use services::services::{
|
||||||
container::ContainerService,
|
container::ContainerService,
|
||||||
git::{ConflictOp, WorktreeResetOptions},
|
git::{ConflictOp, GitCliError, GitServiceError, WorktreeResetOptions},
|
||||||
github::{CreatePrRequest, GitHubService, GitHubServiceError},
|
github::{CreatePrRequest, GitHubService, GitHubServiceError},
|
||||||
};
|
};
|
||||||
use sqlx::Error as SqlxError;
|
use sqlx::Error as SqlxError;
|
||||||
@@ -605,11 +605,21 @@ pub async fn push_task_attempt_branch(
|
|||||||
Ok(ResponseJson(ApiResponse::success(())))
|
Ok(ResponseJson(ApiResponse::success(())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, TS)]
|
||||||
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
|
#[ts(tag = "type", rename_all = "snake_case")]
|
||||||
|
pub enum CreatePrError {
|
||||||
|
GithubCliNotInstalled,
|
||||||
|
GithubCliNotLoggedIn,
|
||||||
|
GitCliNotLoggedIn,
|
||||||
|
GitCliNotInstalled,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_github_pr(
|
pub async fn create_github_pr(
|
||||||
Extension(task_attempt): Extension<TaskAttempt>,
|
Extension(task_attempt): Extension<TaskAttempt>,
|
||||||
State(deployment): State<DeploymentImpl>,
|
State(deployment): State<DeploymentImpl>,
|
||||||
Json(request): Json<CreateGitHubPrRequest>,
|
Json(request): Json<CreateGitHubPrRequest>,
|
||||||
) -> Result<ResponseJson<ApiResponse<String, GitHubServiceError>>, ApiError> {
|
) -> Result<ResponseJson<ApiResponse<String, CreatePrError>>, ApiError> {
|
||||||
let github_config = deployment.config().read().await.github.clone();
|
let github_config = deployment.config().read().await.github.clone();
|
||||||
// Get the task attempt to access the stored target branch
|
// Get the task attempt to access the stored target branch
|
||||||
let target_branch = request.target_branch.unwrap_or_else(|| {
|
let target_branch = request.target_branch.unwrap_or_else(|| {
|
||||||
@@ -642,13 +652,18 @@ pub async fn create_github_pr(
|
|||||||
.push_to_github(&workspace_path, &task_attempt.branch)
|
.push_to_github(&workspace_path, &task_attempt.branch)
|
||||||
{
|
{
|
||||||
tracing::error!("Failed to push branch to GitHub: {}", e);
|
tracing::error!("Failed to push branch to GitHub: {}", e);
|
||||||
let gh_e = GitHubServiceError::from(e);
|
match e {
|
||||||
if gh_e.is_api_data() {
|
GitServiceError::GitCLI(GitCliError::AuthFailed(_)) => {
|
||||||
return Ok(ResponseJson(ApiResponse::error_with_data(gh_e)));
|
return Ok(ResponseJson(ApiResponse::error_with_data(
|
||||||
} else {
|
CreatePrError::GitCliNotLoggedIn,
|
||||||
return Ok(ResponseJson(ApiResponse::error(
|
)));
|
||||||
format!("Failed to push branch to GitHub: {}", gh_e).as_str(),
|
}
|
||||||
)));
|
GitServiceError::GitCLI(GitCliError::NotAvailable) => {
|
||||||
|
return Ok(ResponseJson(ApiResponse::error_with_data(
|
||||||
|
CreatePrError::GitCliNotInstalled,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
_ => return Err(ApiError::GitService(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,12 +738,14 @@ pub async fn create_github_pr(
|
|||||||
task_attempt.id,
|
task_attempt.id,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
if e.is_api_data() {
|
match &e {
|
||||||
Ok(ResponseJson(ApiResponse::error_with_data(e)))
|
GitHubServiceError::GhCliNotInstalled(_) => Ok(ResponseJson(
|
||||||
} else {
|
ApiResponse::error_with_data(CreatePrError::GithubCliNotInstalled),
|
||||||
Ok(ResponseJson(ApiResponse::error(
|
)),
|
||||||
format!("Failed to create PR: {}", e).as_str(),
|
GitHubServiceError::AuthFailed(_) => Ok(ResponseJson(
|
||||||
)))
|
ApiResponse::error_with_data(CreatePrError::GithubCliNotLoggedIn),
|
||||||
|
)),
|
||||||
|
_ => Err(ApiError::GitHubService(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,96 +3,61 @@ use std::time::Duration;
|
|||||||
use backon::{ExponentialBuilder, Retryable};
|
use backon::{ExponentialBuilder, Retryable};
|
||||||
use db::models::merge::PullRequestInfo;
|
use db::models::merge::PullRequestInfo;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use ts_rs::TS;
|
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
|
||||||
use cli::{GhCli, GhCliError};
|
use cli::{GhCli, GhCliError};
|
||||||
|
|
||||||
use crate::services::git::{GitCliError, GitServiceError};
|
#[derive(Debug, Error)]
|
||||||
|
|
||||||
#[derive(Debug, Error, Serialize, Deserialize, TS)]
|
|
||||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
||||||
#[ts(use_ts_enum)]
|
|
||||||
pub enum GitHubServiceError {
|
pub enum GitHubServiceError {
|
||||||
#[ts(skip)]
|
|
||||||
#[error("Repository error: {0}")]
|
#[error("Repository error: {0}")]
|
||||||
Repository(String),
|
Repository(String),
|
||||||
#[ts(skip)]
|
|
||||||
#[error("Pull request error: {0}")]
|
#[error("Pull request error: {0}")]
|
||||||
PullRequest(String),
|
PullRequest(String),
|
||||||
#[error("GitHub token is invalid or expired.")]
|
#[error("GitHub authentication failed: {0}")]
|
||||||
TokenInvalid,
|
AuthFailed(GhCliError),
|
||||||
#[error("Insufficient permissions")]
|
#[error("Insufficient permissions: {0}")]
|
||||||
InsufficientPermissions,
|
InsufficientPermissions(GhCliError),
|
||||||
#[error("GitHub repository not found or no access")]
|
#[error("GitHub repository not found or no access: {0}")]
|
||||||
RepoNotFoundOrNoAccess,
|
RepoNotFoundOrNoAccess(GhCliError),
|
||||||
#[error(
|
#[error(
|
||||||
"GitHub CLI is not installed or not available in PATH. Please install it from https://cli.github.com/ and authenticate with 'gh auth login'"
|
"GitHub CLI is not installed or not available in PATH. Please install it from https://cli.github.com/ and authenticate with 'gh auth login'"
|
||||||
)]
|
)]
|
||||||
GhCliNotInstalled,
|
GhCliNotInstalled(GhCliError),
|
||||||
#[ts(skip)]
|
|
||||||
#[serde(skip)]
|
|
||||||
#[error(transparent)]
|
|
||||||
GitService(GitServiceError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<GhCliError> for GitHubServiceError {
|
impl From<GhCliError> for GitHubServiceError {
|
||||||
fn from(error: GhCliError) -> Self {
|
fn from(error: GhCliError) -> Self {
|
||||||
match error {
|
match &error {
|
||||||
GhCliError::AuthFailed(_) => Self::TokenInvalid,
|
GhCliError::AuthFailed(_) => Self::AuthFailed(error),
|
||||||
GhCliError::NotAvailable => Self::GhCliNotInstalled,
|
GhCliError::NotAvailable => Self::GhCliNotInstalled(error),
|
||||||
GhCliError::CommandFailed(msg) => {
|
GhCliError::CommandFailed(msg) => {
|
||||||
let lower = msg.to_ascii_lowercase();
|
let lower = msg.to_ascii_lowercase();
|
||||||
if lower.contains("403") || lower.contains("forbidden") {
|
if lower.contains("403") || lower.contains("forbidden") {
|
||||||
Self::InsufficientPermissions
|
Self::InsufficientPermissions(error)
|
||||||
} else if lower.contains("404") || lower.contains("not found") {
|
} else if lower.contains("404") || lower.contains("not found") {
|
||||||
Self::RepoNotFoundOrNoAccess
|
Self::RepoNotFoundOrNoAccess(error)
|
||||||
} else {
|
} else {
|
||||||
Self::PullRequest(msg)
|
Self::PullRequest(msg.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GhCliError::UnexpectedOutput(msg) => Self::PullRequest(msg),
|
GhCliError::UnexpectedOutput(msg) => Self::PullRequest(msg.to_string()),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<GitServiceError> for GitHubServiceError {
|
|
||||||
fn from(error: GitServiceError) -> Self {
|
|
||||||
match error {
|
|
||||||
GitServiceError::GitCLI(GitCliError::AuthFailed(_)) => Self::TokenInvalid,
|
|
||||||
GitServiceError::GitCLI(GitCliError::CommandFailed(msg)) => {
|
|
||||||
let lower = msg.to_ascii_lowercase();
|
|
||||||
if lower.contains("the requested url returned error: 403") {
|
|
||||||
Self::InsufficientPermissions
|
|
||||||
} else if lower.contains("the requested url returned error: 404") {
|
|
||||||
Self::RepoNotFoundOrNoAccess
|
|
||||||
} else {
|
|
||||||
Self::GitService(GitServiceError::GitCLI(GitCliError::CommandFailed(msg)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => Self::GitService(other),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GitHubServiceError {
|
impl GitHubServiceError {
|
||||||
pub fn is_api_data(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
GitHubServiceError::TokenInvalid
|
|
||||||
| GitHubServiceError::InsufficientPermissions
|
|
||||||
| GitHubServiceError::RepoNotFoundOrNoAccess
|
|
||||||
| GitHubServiceError::GhCliNotInstalled
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn should_retry(&self) -> bool {
|
pub fn should_retry(&self) -> bool {
|
||||||
!self.is_api_data()
|
!matches!(
|
||||||
|
self,
|
||||||
|
GitHubServiceError::AuthFailed(_)
|
||||||
|
| GitHubServiceError::InsufficientPermissions(_)
|
||||||
|
| GitHubServiceError::RepoNotFoundOrNoAccess(_)
|
||||||
|
| GitHubServiceError::GhCliNotInstalled(_)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,8 +133,8 @@ impl GitHubService {
|
|||||||
))
|
))
|
||||||
})?
|
})?
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
GhCliError::NotAvailable => GitHubServiceError::GhCliNotInstalled,
|
GhCliError::NotAvailable => GitHubServiceError::GhCliNotInstalled(err),
|
||||||
GhCliError::AuthFailed(_) => GitHubServiceError::TokenInvalid,
|
GhCliError::AuthFailed(_) => GitHubServiceError::AuthFailed(err),
|
||||||
GhCliError::CommandFailed(msg) => {
|
GhCliError::CommandFailed(msg) => {
|
||||||
GitHubServiceError::Repository(format!("GitHub CLI auth check failed: {msg}"))
|
GitHubServiceError::Repository(format!("GitHub CLI auth check failed: {msg}"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { attemptsApi } from '@/lib/api.ts';
|
import { attemptsApi } from '@/lib/api.ts';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
import { GitBranch, TaskAttempt, TaskWithAttemptStatus } from 'shared/types';
|
||||||
GitBranch,
|
|
||||||
GitHubServiceError,
|
|
||||||
TaskAttempt,
|
|
||||||
TaskWithAttemptStatus,
|
|
||||||
} from 'shared/types';
|
|
||||||
import { projectsApi } from '@/lib/api.ts';
|
import { projectsApi } from '@/lib/api.ts';
|
||||||
import { Loader2 } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
import NiceModal, { useModal } from '@ebay/nice-modal-react';
|
import NiceModal, { useModal } from '@ebay/nice-modal-react';
|
||||||
@@ -166,49 +161,34 @@ const CreatePRDialogImpl = NiceModal.create<CreatePRDialogProps>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
switch (result.error) {
|
if (
|
||||||
case GitHubServiceError.GH_CLI_NOT_INSTALLED: {
|
result.error.type === 'github_cli_not_installed' ||
|
||||||
if (isMacEnvironment) {
|
result.error.type === 'github_cli_not_logged_in'
|
||||||
await showGhCliSetupDialog();
|
) {
|
||||||
} else {
|
if (isMacEnvironment) {
|
||||||
const ui = mapGhCliErrorToUi(
|
await showGhCliSetupDialog();
|
||||||
'SETUP_HELPER_NOT_SUPPORTED',
|
} else {
|
||||||
defaultGhCliErrorMessage,
|
const ui = mapGhCliErrorToUi(
|
||||||
t
|
'SETUP_HELPER_NOT_SUPPORTED',
|
||||||
);
|
defaultGhCliErrorMessage,
|
||||||
setGhCliHelp(ui.variant ? ui : null);
|
t
|
||||||
setError(ui.variant ? null : ui.message);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case GitHubServiceError.TOKEN_INVALID: {
|
|
||||||
if (isMacEnvironment) {
|
|
||||||
await showGhCliSetupDialog();
|
|
||||||
} else {
|
|
||||||
const ui = mapGhCliErrorToUi(
|
|
||||||
'SETUP_HELPER_NOT_SUPPORTED',
|
|
||||||
defaultGhCliErrorMessage,
|
|
||||||
t
|
|
||||||
);
|
|
||||||
setGhCliHelp(ui.variant ? ui : null);
|
|
||||||
setError(ui.variant ? null : ui.message);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case GitHubServiceError.INSUFFICIENT_PERMISSIONS:
|
|
||||||
setError(t('createPrDialog.errors.insufficientPermissions'));
|
|
||||||
setGhCliHelp(null);
|
|
||||||
return;
|
|
||||||
case GitHubServiceError.REPO_NOT_FOUND_OR_NO_ACCESS:
|
|
||||||
setError(t('createPrDialog.errors.repoNotFoundOrNoAccess'));
|
|
||||||
setGhCliHelp(null);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
setError(
|
|
||||||
result.message || t('createPrDialog.errors.failedToCreate')
|
|
||||||
);
|
);
|
||||||
setGhCliHelp(null);
|
setGhCliHelp(ui.variant ? ui : null);
|
||||||
return;
|
setError(ui.variant ? null : ui.message);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (
|
||||||
|
result.error.type === 'git_cli_not_installed' ||
|
||||||
|
result.error.type === 'git_cli_not_logged_in'
|
||||||
|
) {
|
||||||
|
const gitCliErrorKey =
|
||||||
|
result.error.type === 'git_cli_not_logged_in'
|
||||||
|
? 'createPrDialog.errors.gitCliNotLoggedIn'
|
||||||
|
: 'createPrDialog.errors.gitCliNotInstalled';
|
||||||
|
|
||||||
|
setError(result.message || t(gitCliErrorKey));
|
||||||
|
setGhCliHelp(null);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -341,7 +341,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"insufficientPermissions": "Insufficient permissions. Please ensure the GitHub CLI has the necessary permissions.",
|
"insufficientPermissions": "Insufficient permissions. Please ensure the GitHub CLI has the necessary permissions.",
|
||||||
"repoNotFoundOrNoAccess": "Repository not found or no access. Please check your repository access and ensure you are authenticated.",
|
"repoNotFoundOrNoAccess": "Repository not found or no access. Please check your repository access and ensure you are authenticated.",
|
||||||
"failedToCreate": "Failed to create GitHub PR"
|
"failedToCreate": "Failed to create GitHub PR",
|
||||||
|
"gitCliNotLoggedIn": "Git is not authenticated. Run \"gh auth login\" (or configure Git credentials) and try again.",
|
||||||
|
"gitCliNotInstalled": "Git CLI is not installed. Install Git to create a PR."
|
||||||
},
|
},
|
||||||
"loginRequired": {
|
"loginRequired": {
|
||||||
"title": "Sign in to create a pull request",
|
"title": "Sign in to create a pull request",
|
||||||
|
|||||||
@@ -117,7 +117,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"insufficientPermissions": "Permisos insuficientes. Por favor asegúrate de que la CLI de GitHub tenga los permisos necesarios.",
|
"insufficientPermissions": "Permisos insuficientes. Por favor asegúrate de que la CLI de GitHub tenga los permisos necesarios.",
|
||||||
"repoNotFoundOrNoAccess": "Repositorio no encontrado o sin acceso. Por favor verifica el acceso al repositorio y asegúrate de estar autenticado.",
|
"repoNotFoundOrNoAccess": "Repositorio no encontrado o sin acceso. Por favor verifica el acceso al repositorio y asegúrate de estar autenticado.",
|
||||||
"failedToCreate": "Error al crear PR de GitHub"
|
"failedToCreate": "Error al crear PR de GitHub",
|
||||||
|
"gitCliNotLoggedIn": "Git no está autenticado. Ejecuta \"gh auth login\" (o configura las credenciales de Git) e inténtalo de nuevo.",
|
||||||
|
"gitCliNotInstalled": "Git CLI no está instalado. Instala Git para crear una PR."
|
||||||
},
|
},
|
||||||
"loginRequired": {
|
"loginRequired": {
|
||||||
"title": "Inicia sesión para crear un pull request",
|
"title": "Inicia sesión para crear un pull request",
|
||||||
|
|||||||
@@ -117,7 +117,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"insufficientPermissions": "権限が不足しています。GitHub CLIに必要な権限があることを確認してください。",
|
"insufficientPermissions": "権限が不足しています。GitHub CLIに必要な権限があることを確認してください。",
|
||||||
"repoNotFoundOrNoAccess": "リポジトリが見つからないか、アクセス権がありません。リポジトリへのアクセス権を確認し、認証されていることを確認してください。",
|
"repoNotFoundOrNoAccess": "リポジトリが見つからないか、アクセス権がありません。リポジトリへのアクセス権を確認し、認証されていることを確認してください。",
|
||||||
"failedToCreate": "GitHub PRの作成に失敗しました"
|
"failedToCreate": "GitHub PRの作成に失敗しました",
|
||||||
|
"gitCliNotLoggedIn": "Gitが認証されていません。\"gh auth login\" を実行するかGitの認証情報を設定してから再試行してください。",
|
||||||
|
"gitCliNotInstalled": "Git CLIがインストールされていません。PRを作成するにはGitをインストールしてください。"
|
||||||
},
|
},
|
||||||
"loginRequired": {
|
"loginRequired": {
|
||||||
"title": "プルリクエストを作成するにはサインインしてください",
|
"title": "プルリクエストを作成するにはサインインしてください",
|
||||||
|
|||||||
@@ -117,7 +117,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"insufficientPermissions": "권한이 부족합니다. GitHub CLI에 필요한 권한이 있는지 확인하세요.",
|
"insufficientPermissions": "권한이 부족합니다. GitHub CLI에 필요한 권한이 있는지 확인하세요.",
|
||||||
"repoNotFoundOrNoAccess": "저장소를 찾을 수 없거나 액세스 권한이 없습니다. 저장소 액세스를 확인하고 인증되었는지 확인하세요.",
|
"repoNotFoundOrNoAccess": "저장소를 찾을 수 없거나 액세스 권한이 없습니다. 저장소 액세스를 확인하고 인증되었는지 확인하세요.",
|
||||||
"failedToCreate": "GitHub PR 생성에 실패했습니다"
|
"failedToCreate": "GitHub PR 생성에 실패했습니다",
|
||||||
|
"gitCliNotLoggedIn": "Git이 인증되지 않았습니다. \"gh auth login\"을 실행하거나 Git 자격 증명을 설정한 후 다시 시도하세요.",
|
||||||
|
"gitCliNotInstalled": "Git CLI가 설치되어 있지 않습니다. PR을 생성하려면 Git을 설치하세요."
|
||||||
},
|
},
|
||||||
"loginRequired": {
|
"loginRequired": {
|
||||||
"title": "Pull Request를 만들려면 로그인하세요",
|
"title": "Pull Request를 만들려면 로그인하세요",
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import {
|
|||||||
UpdateTask,
|
UpdateTask,
|
||||||
UpdateTag,
|
UpdateTag,
|
||||||
UserSystemInfo,
|
UserSystemInfo,
|
||||||
GitHubServiceError,
|
|
||||||
UpdateRetryFollowUpDraftRequest,
|
UpdateRetryFollowUpDraftRequest,
|
||||||
McpServerQuery,
|
McpServerQuery,
|
||||||
UpdateMcpServersBody,
|
UpdateMcpServersBody,
|
||||||
@@ -71,6 +70,7 @@ import {
|
|||||||
CommitCompareResult,
|
CommitCompareResult,
|
||||||
OpenEditorResponse,
|
OpenEditorResponse,
|
||||||
OpenEditorRequest,
|
OpenEditorRequest,
|
||||||
|
CreatePrError,
|
||||||
} from 'shared/types';
|
} from 'shared/types';
|
||||||
|
|
||||||
// Re-export types for convenience
|
// Re-export types for convenience
|
||||||
@@ -615,12 +615,12 @@ export const attemptsApi = {
|
|||||||
createPR: async (
|
createPR: async (
|
||||||
attemptId: string,
|
attemptId: string,
|
||||||
data: CreateGitHubPrRequest
|
data: CreateGitHubPrRequest
|
||||||
): Promise<Result<string, GitHubServiceError>> => {
|
): Promise<Result<string, CreatePrError>> => {
|
||||||
const response = await makeRequest(`/api/task-attempts/${attemptId}/pr`, {
|
const response = await makeRequest(`/api/task-attempts/${attemptId}/pr`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
return handleApiResponseAsResult<string, GitHubServiceError>(response);
|
return handleApiResponseAsResult<string, CreatePrError>(response);
|
||||||
},
|
},
|
||||||
|
|
||||||
startDevServer: async (attemptId: string): Promise<void> => {
|
startDevServer: async (attemptId: string): Promise<void> => {
|
||||||
|
|||||||
@@ -174,8 +174,6 @@ export type CreateGitHubPrRequest = { title: string, body: string | null, target
|
|||||||
|
|
||||||
export type ImageResponse = { id: string, file_path: string, original_name: string, mime_type: string | null, size_bytes: bigint, hash: string, created_at: string, updated_at: string, };
|
export type ImageResponse = { id: string, file_path: string, original_name: string, mime_type: string | null, size_bytes: bigint, hash: string, created_at: string, updated_at: string, };
|
||||||
|
|
||||||
export enum GitHubServiceError { TOKEN_INVALID = "TOKEN_INVALID", INSUFFICIENT_PERMISSIONS = "INSUFFICIENT_PERMISSIONS", REPO_NOT_FOUND_OR_NO_ACCESS = "REPO_NOT_FOUND_OR_NO_ACCESS", GH_CLI_NOT_INSTALLED = "GH_CLI_NOT_INSTALLED" }
|
|
||||||
|
|
||||||
export type Config = { config_version: string, theme: ThemeMode, executor_profile: ExecutorProfileId, disclaimer_acknowledged: boolean, onboarding_acknowledged: boolean, notifications: NotificationConfig, editor: EditorConfig, github: GitHubConfig, analytics_enabled: boolean, workspace_dir: string | null, last_app_version: string | null, show_release_notes: boolean, language: UiLanguage, git_branch_prefix: string, showcases: ShowcaseState, };
|
export type Config = { config_version: string, theme: ThemeMode, executor_profile: ExecutorProfileId, disclaimer_acknowledged: boolean, onboarding_acknowledged: boolean, notifications: NotificationConfig, editor: EditorConfig, github: GitHubConfig, analytics_enabled: boolean, workspace_dir: string | null, last_app_version: string | null, show_release_notes: boolean, language: UiLanguage, git_branch_prefix: string, showcases: ShowcaseState, };
|
||||||
|
|
||||||
export type NotificationConfig = { sound_enabled: boolean, push_enabled: boolean, sound_file: SoundFile, };
|
export type NotificationConfig = { sound_enabled: boolean, push_enabled: boolean, sound_file: SoundFile, };
|
||||||
@@ -300,6 +298,8 @@ export type RebaseTaskAttemptRequest = { old_base_branch: string | null, new_bas
|
|||||||
|
|
||||||
export type GitOperationError = { "type": "merge_conflicts", message: string, op: ConflictOp, } | { "type": "rebase_in_progress" };
|
export type GitOperationError = { "type": "merge_conflicts", message: string, op: ConflictOp, } | { "type": "rebase_in_progress" };
|
||||||
|
|
||||||
|
export type CreatePrError = { "type": "github_cli_not_installed" } | { "type": "github_cli_not_logged_in" } | { "type": "git_cli_not_logged_in" } | { "type": "git_cli_not_installed" };
|
||||||
|
|
||||||
export type CommitInfo = { sha: string, subject: string, };
|
export type CommitInfo = { sha: string, subject: string, };
|
||||||
|
|
||||||
export type BranchStatus = { commits_behind: number | null, commits_ahead: number | null, has_uncommitted_changes: boolean | null, head_oid: string | null, uncommitted_count: number | null, untracked_count: number | null, target_branch_name: string, remote_commits_behind: number | null, remote_commits_ahead: number | null, merges: Array<Merge>,
|
export type BranchStatus = { commits_behind: number | null, commits_ahead: number | null, has_uncommitted_changes: boolean | null, head_oid: string | null, uncommitted_count: number | null, untracked_count: number | null, target_branch_name: string, remote_commits_behind: number | null, remote_commits_ahead: number | null, merges: Array<Merge>,
|
||||||
|
|||||||
Reference in New Issue
Block a user