diff --git a/apps/desktop/src/components/NewCommitView.svelte b/apps/desktop/src/components/NewCommitView.svelte index 85d768fed3..ff977826d6 100644 --- a/apps/desktop/src/components/NewCommitView.svelte +++ b/apps/desktop/src/components/NewCommitView.svelte @@ -32,6 +32,7 @@ const laneState = $derived(uiState.lane(stackId || 'new-commit-view--new-stack')); const [createCommitInStack, commitCreation] = stackService.createCommit(); + const [runMessageHook] = hooksService.message; let isCooking = $state(false); @@ -87,7 +88,7 @@ // Run commit-msg hook if hooks are enabled let finalMessage = message; if ($runCommitHooks) { - const messageHookResult = await hooksService.message(projectId, message); + const messageHookResult = await runMessageHook({ projectId, message }); if (messageHookResult?.status === 'failure') { showError('Commit message hook failed', messageHookResult.error); return; diff --git a/apps/desktop/src/lib/bootstrap/deps.ts b/apps/desktop/src/lib/bootstrap/deps.ts index 30f3d55147..d0a9a4027d 100644 --- a/apps/desktop/src/lib/bootstrap/deps.ts +++ b/apps/desktop/src/lib/bootstrap/deps.ts @@ -187,7 +187,7 @@ export function initDependencies(args: { const branchService = new BranchService(clientState['backendApi']); const cherryApplyService = new CherryApplyService(clientState.backendApi); const remotesService = new RemotesService(backend); - const hooksService = new HooksService(backend); + const hooksService = new HooksService(clientState.backendApi); // ============================================================================ // STACKS & WORKSPACE MANAGEMENT diff --git a/apps/desktop/src/lib/commits/dropHandler.ts b/apps/desktop/src/lib/commits/dropHandler.ts index c3f704ce7b..a9c0f140c8 100644 --- a/apps/desktop/src/lib/commits/dropHandler.ts +++ b/apps/desktop/src/lib/commits/dropHandler.ts @@ -339,7 +339,13 @@ export class AmendCommitWithHunkDzHandler implements DropzoneHandler { commitId: commit.id, worktreeChanges }); - await this.args.hooksService.runPostCommitHooks(projectId); + if (runHooks) { + try { + await this.args.hooksService.runPostCommitHooks(projectId); + } catch { + return; + } + } } } } diff --git a/apps/desktop/src/lib/hooks/hooksService.ts b/apps/desktop/src/lib/hooks/hooksService.ts index b5ca4eb90d..6ac1724f8e 100644 --- a/apps/desktop/src/lib/hooks/hooksService.ts +++ b/apps/desktop/src/lib/hooks/hooksService.ts @@ -1,7 +1,7 @@ import { InjectionToken } from '@gitbutler/core/context'; import { chipToasts } from '@gitbutler/ui'; -import type { IBackend } from '$lib/backend'; import type { DiffSpec } from '$lib/hunks/hunk'; +import type { BackendApi } from '$lib/state/clientState.svelte'; export type HookStatus = | { @@ -34,37 +34,29 @@ export type MessageHookStatus = export const HOOKS_SERVICE = new InjectionToken('HooksService'); export class HooksService { - constructor(private backend: IBackend) {} + private api: ReturnType; - async preCommitDiffspecs(projectId: string, changes: DiffSpec[]) { - return await this.backend.invoke('pre_commit_hook_diffspecs', { - projectId, - changes - }); + constructor(backendApi: BackendApi) { + this.api = injectEndpoints(backendApi); } - async postCommit(projectId: string) { - return await this.backend.invoke('post_commit_hook', { - projectId - }); - } - - async message(projectId: string, message: string) { - return await this.backend.invoke('message_hook', { - projectId, - message - }); + get message() { + return this.api.endpoints.message.useMutation(); } + // Promise-based wrapper methods with toast handling async runPreCommitHooks(projectId: string, changes: DiffSpec[]): Promise { const loadingToastId = chipToasts.loading('Started pre-commit hooks'); try { - const result = await this.preCommitDiffspecs(projectId, changes); + const result = await this.api.endpoints.preCommitDiffspecs.mutate({ + projectId, + changes + }); if (result?.status === 'failure') { chipToasts.removeChipToast(loadingToastId); - throw new Error(result.error); + throw new Error(formatError(result.error)); } chipToasts.removeChipToast(loadingToastId); @@ -79,11 +71,13 @@ export class HooksService { const loadingToastId = chipToasts.loading('Started post-commit hooks'); try { - const result = await this.postCommit(projectId); + const result = await this.api.endpoints.postCommit.mutate({ + projectId + }); if (result?.status === 'failure') { chipToasts.removeChipToast(loadingToastId); - throw new Error(result.error); + throw new Error(formatError(result.error)); } chipToasts.removeChipToast(loadingToastId); @@ -94,3 +88,26 @@ export class HooksService { } } } + +function formatError(error: string): string { + return `${error}\n\nIf you don't want git hooks to be run, you can disable them in the project settings.`; +} + +function injectEndpoints(backendApi: BackendApi) { + return backendApi.injectEndpoints({ + endpoints: (build) => ({ + preCommitDiffspecs: build.mutation({ + extraOptions: { command: 'pre_commit_hook_diffspecs' }, + query: (args) => args + }), + postCommit: build.mutation({ + extraOptions: { command: 'post_commit_hook' }, + query: (args) => args + }), + message: build.mutation({ + extraOptions: { command: 'message_hook' }, + query: (args) => args + }) + }) + }); +}