From e7d17dcef295e3cebf47093a8e23b06a371e5ab2 Mon Sep 17 00:00:00 2001 From: Alessandro Pogliaghi Date: Tue, 28 Jul 2026 16:41:33 +0100 Subject: [PATCH] fix(git): handle missing remote branch comparisons Generated-By: PostHog Code Task-Id: 1d6efd63-cb24-47c2-aa8b-b05239df349f --- .../src/services/git/service.test.ts | 87 +++++++++++++++++++ .../src/services/git/service.ts | 3 + 2 files changed, 90 insertions(+) create mode 100644 packages/workspace-server/src/services/git/service.test.ts diff --git a/packages/workspace-server/src/services/git/service.test.ts b/packages/workspace-server/src/services/git/service.test.ts new file mode 100644 index 0000000000..83c92ef09d --- /dev/null +++ b/packages/workspace-server/src/services/git/service.test.ts @@ -0,0 +1,87 @@ +import type { GhExecResult } from "@posthog/git/gh"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const execGhMock = vi.hoisted(() => vi.fn()); + +vi.mock("@posthog/git/gh", () => ({ execGh: execGhMock })); + +import { GitService } from "./service"; + +function ghResult(overrides: Partial = {}): GhExecResult { + return { + stdout: "", + stderr: "", + exitCode: 0, + ...overrides, + }; +} + +describe("GitService", () => { + beforeEach(() => { + execGhMock.mockReset(); + }); + + it("returns no changed files when the remote branch does not exist yet", async () => { + execGhMock + .mockResolvedValueOnce(ghResult({ stdout: "main\n" })) + .mockResolvedValueOnce( + ghResult({ + stderr: "gh: Not Found (HTTP 404)\n", + exitCode: 1, + }), + ); + + await expect( + new GitService().getBranchChangedFiles("posthog/code", "feature/new"), + ).resolves.toEqual([]); + }); + + it("returns changed files from a successful comparison", async () => { + execGhMock + .mockResolvedValueOnce(ghResult({ stdout: "main\n" })) + .mockResolvedValueOnce( + ghResult({ + stdout: JSON.stringify({ + files: [ + { + filename: "src/example.ts", + status: "added", + additions: 3, + deletions: 0, + sha: "abc123", + }, + ], + }), + }), + ); + + await expect( + new GitService().getBranchChangedFiles("posthog/code", "feature/new"), + ).resolves.toEqual([ + { + path: "src/example.ts", + status: "added", + originalPath: undefined, + linesAdded: 3, + linesRemoved: 0, + sha: "abc123", + patch: undefined, + }, + ]); + }); + + it("preserves non-404 comparison failures", async () => { + execGhMock + .mockResolvedValueOnce(ghResult({ stdout: "main\n" })) + .mockResolvedValueOnce( + ghResult({ + stderr: "gh: authentication failed (HTTP 401)\n", + exitCode: 1, + }), + ); + + await expect( + new GitService().getBranchChangedFiles("posthog/code", "feature/new"), + ).rejects.toThrow("Failed to fetch branch files"); + }); +}); diff --git a/packages/workspace-server/src/services/git/service.ts b/packages/workspace-server/src/services/git/service.ts index 361905139f..71447cc0eb 100644 --- a/packages/workspace-server/src/services/git/service.ts +++ b/packages/workspace-server/src/services/git/service.ts @@ -1236,6 +1236,9 @@ export class GitService extends TypedEventEmitter { ]); if (result.exitCode !== 0) { + if (/HTTP 404\b/.test(`${result.stderr} ${result.error ?? ""}`)) { + return []; + } throw new Error( `Failed to fetch branch files: ${result.stderr || result.error || "Unknown error"}`, );