Files
paseo/packages/protocol/src/git-remote.test.ts
T
Li Mu ZhiandClaude Opus 4.8 869edcbf11 fix(forge): preserve non-default port in forge web URLs (#2478)
"Open in browser" links for a self-hosted forge served on a non-standard
port (e.g. Forgejo/Gitea on :60443) dropped the port, producing
https://host/owner/repo/... instead of https://host:60443/owner/repo/...,
which 404s or hits the wrong service.

parseGitRemoteLocation discarded parsed.port (GitRemoteLocation had no
port field), and buildForgeBranchTreeUrl / buildForgeBlobUrl rebuilt the
origin from the portless host. Preserve the port on GitRemoteLocation and
reattach it in the web-URL builders, only for self-hosted http(s) origins
(an SSH port isn't the web port; a canonicalized cloud host uses the
default port). Host-identity matching (forge detection, cloud-host checks)
stays port-agnostic.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 04:00:46 +08:00

52 lines
2.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { isCompleteGitRemote, parseGitRemoteLocation } from "./git-remote.js";
describe("isCompleteGitRemote", () => {
it("treats supported URLs and scp-like addresses as complete remotes", () => {
expect(isCompleteGitRemote("https://github.com/owner/repo")).toBe(true);
expect(isCompleteGitRemote("http://internal/owner/repo.git")).toBe(true);
expect(isCompleteGitRemote("ssh://git@github.com/owner/repo")).toBe(true);
expect(isCompleteGitRemote("git@github.com:owner/repo.git")).toBe(true);
expect(isCompleteGitRemote(" https://github.com/owner/repo ")).toBe(true);
});
it("treats owner/repo shorthand as incomplete (needs a clone protocol)", () => {
expect(isCompleteGitRemote("owner/repo")).toBe(false);
expect(isCompleteGitRemote("owner/repo.git")).toBe(false);
expect(isCompleteGitRemote("")).toBe(false);
});
it("rejects schemes the daemon's parser does not accept, so clients agree with the server", () => {
// The old client-side regex matched any `scheme://`, classifying these as
// complete URLs while the daemon (parseGitRemoteLocation) rejected them —
// producing a confusing "use owner/repo format" error. The shared helper
// must classify them identically to the daemon.
for (const repo of ["git://github.com/owner/repo", "ftp://host/repo", "file:///tmp/repo"]) {
expect(isCompleteGitRemote(repo)).toBe(false);
expect(parseGitRemoteLocation(repo)).toBeNull();
}
});
});
describe("parseGitRemoteLocation port", () => {
it("preserves an explicit non-default port from an https remote", () => {
expect(parseGitRemoteLocation("https://home-git.example.com:60443/team/repo.git")?.port).toBe(
"60443",
);
});
it("preserves a port from a plain http remote", () => {
expect(parseGitRemoteLocation("http://internal.example.com:3000/team/repo.git")?.port).toBe(
"3000",
);
});
it("omits the port for a default-port remote", () => {
expect(parseGitRemoteLocation("https://github.com/acme/repo.git")?.port).toBeUndefined();
});
it("has no port for an scp-form remote", () => {
expect(parseGitRemoteLocation("git@host.example.com:team/repo.git")?.port).toBeUndefined();
});
});