diff --git a/CHANGELOG.md b/CHANGELOG.md index d4cc114c0..a0bf5e9ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [ask sb] Fixed issue where reasoning tokens would appear in `text` content for openai compatible models. [#582](https://github.com/sourcebot-dev/sourcebot/pull/582) - Fixed issue with GitHub app token tracking and refreshing. [#583](https://github.com/sourcebot-dev/sourcebot/pull/583) - Fixed "The account is already associated with another user" errors with GitLab oauth provider. [#584](https://github.com/sourcebot-dev/sourcebot/pull/584) +- Fixed error when viewing a generic git connection in `/settings/connections`. [#588](https://github.com/sourcebot-dev/sourcebot/pull/588) ## [4.8.1] - 2025-10-29 diff --git a/packages/backend/src/constants.ts b/packages/backend/src/constants.ts index 9ba858de3..f073bac5f 100644 --- a/packages/backend/src/constants.ts +++ b/packages/backend/src/constants.ts @@ -1,9 +1,10 @@ +import { CodeHostType } from "@sourcebot/db"; import { env } from "./env.js"; import path from "path"; export const SINGLE_TENANT_ORG_ID = 1; -export const PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES = [ +export const PERMISSION_SYNC_SUPPORTED_CODE_HOST_TYPES: CodeHostType[] = [ 'github', 'gitlab', ]; diff --git a/packages/backend/src/repoCompileUtils.ts b/packages/backend/src/repoCompileUtils.ts index 8e8b1f268..d31725433 100644 --- a/packages/backend/src/repoCompileUtils.ts +++ b/packages/backend/src/repoCompileUtils.ts @@ -7,7 +7,7 @@ import { BitbucketRepository, getBitbucketReposFromConfig } from "./bitbucket.js import { getAzureDevOpsReposFromConfig } from "./azuredevops.js"; import { SchemaRestRepository as BitbucketServerRepository } from "@coderabbitai/bitbucket/server/openapi"; import { SchemaRepository as BitbucketCloudRepository } from "@coderabbitai/bitbucket/cloud/openapi"; -import { Prisma, PrismaClient } from '@sourcebot/db'; +import { CodeHostType, Prisma, PrismaClient } from '@sourcebot/db'; import { WithRequired } from "./types.js" import { marshalBool } from "./utils.js"; import { createLogger } from '@sourcebot/logger'; @@ -392,7 +392,7 @@ export const compileBitbucketConfig = async ( const repos = bitbucketRepos.map((repo) => { const isServer = config.deploymentType === 'server'; - const codeHostType = isServer ? 'bitbucket-server' : 'bitbucket-cloud'; // zoekt expects bitbucket-server + const codeHostType: CodeHostType = isServer ? 'bitbucketServer' : 'bitbucketCloud'; const displayName = isServer ? (repo as BitbucketServerRepository).name! : (repo as BitbucketCloudRepository).full_name!; const externalId = isServer ? (repo as BitbucketServerRepository).id!.toString() : (repo as BitbucketCloudRepository).uuid!; const isPublic = isServer ? (repo as BitbucketServerRepository).public : (repo as BitbucketCloudRepository).is_private === false; @@ -425,7 +425,8 @@ export const compileBitbucketConfig = async ( }, metadata: { gitConfig: { - 'zoekt.web-url-type': codeHostType, + // zoekt expects bitbucket-server and bitbucket-cloud + 'zoekt.web-url-type': codeHostType === 'bitbucketServer' ? 'bitbucket-server' : 'bitbucket-cloud', 'zoekt.web-url': webUrl, 'zoekt.name': repoName, 'zoekt.archived': marshalBool(isArchived), @@ -507,7 +508,7 @@ export const compileGenericGitHostConfig_file = async ( const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, '')); const repo: RepoData = { - external_codeHostType: 'generic-git-host', + external_codeHostType: 'genericGitHost', external_codeHostUrl: remoteUrl.resource, external_id: remoteUrl.toString(), cloneUrl: `file://${repoPath}`, @@ -571,7 +572,7 @@ export const compileGenericGitHostConfig_url = async ( const repoName = path.join(remoteUrl.host, remoteUrl.pathname.replace(/\.git$/, '')); const repo: RepoData = { - external_codeHostType: 'generic-git-host', + external_codeHostType: 'genericGitHost', external_codeHostUrl: remoteUrl.origin, external_id: remoteUrl.toString(), cloneUrl: remoteUrl.toString(), diff --git a/packages/backend/src/utils.ts b/packages/backend/src/utils.ts index 4bb18549f..0fe980985 100644 --- a/packages/backend/src/utils.ts +++ b/packages/backend/src/utils.ts @@ -59,7 +59,7 @@ export const getRepoPath = (repo: Repo): { path: string, isReadOnly: boolean } = // If we are dealing with a local repository, then use that as the path. // Mark as read-only since we aren't guaranteed to have write access to the local filesystem. const cloneUrl = new URL(repo.cloneUrl); - if (repo.external_codeHostType === 'generic-git-host' && cloneUrl.protocol === 'file:') { + if (repo.external_codeHostType === 'genericGitHost' && cloneUrl.protocol === 'file:') { return { path: cloneUrl.pathname, isReadOnly: true, diff --git a/packages/db/prisma/migrations/20251031012851_change_connection_type_to_enum/migration.sql b/packages/db/prisma/migrations/20251031012851_change_connection_type_to_enum/migration.sql new file mode 100644 index 000000000..6580b522b --- /dev/null +++ b/packages/db/prisma/migrations/20251031012851_change_connection_type_to_enum/migration.sql @@ -0,0 +1,14 @@ +/* + Migrates the `connectionType` column from text to a enum. The values in this field are known to + be one of the following: github, gitlab, gitea, gerrit, bitbucket, azuredevops, git. + + This is occording to what we would expect to be in a valid config file for the schema version at commit 4899c9fbc755851af2ddcce99f4a4200f2faa4f6. + See: https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/schemas/src/v3/connection.type.ts#L3 +*/ +-- CreateEnum +CREATE TYPE "ConnectionType" AS ENUM ('github', 'gitlab', 'gitea', 'gerrit', 'bitbucket', 'azuredevops', 'git'); + +-- AlterTable - Convert existing column to enum type without dropping data +ALTER TABLE "Connection" + ALTER COLUMN "connectionType" TYPE "ConnectionType" + USING "connectionType"::text::"ConnectionType"; diff --git a/packages/db/prisma/migrations/20251031014307_change_repo_code_host_type_to_enum/migration.sql b/packages/db/prisma/migrations/20251031014307_change_repo_code_host_type_to_enum/migration.sql new file mode 100644 index 000000000..1d3fb23b1 --- /dev/null +++ b/packages/db/prisma/migrations/20251031014307_change_repo_code_host_type_to_enum/migration.sql @@ -0,0 +1,22 @@ +/* + Migrates the `external_codeHostType` column from text to a enum. The values in this field are known to + be one of the following: github, gitlab, gitea, gerrit, bitbucket-server, bitbucket-cloud, generic-git-host, azuredevops. + + This is occording to what we would expect to be in the database written as of commit 4899c9fbc755851af2ddcce99f4a4200f2faa4f6. + See: + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L57 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L135 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L208 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L291 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L407 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L510 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L574 + - https://github.com/sourcebot-dev/sourcebot/blob/4899c9fbc755851af2ddcce99f4a4200f2faa4f6/packages/backend/src/repoCompileUtils.ts#L642 +*/ +-- CreateEnum +CREATE TYPE "CodeHostType" AS ENUM ('github', 'gitlab', 'gitea', 'gerrit', 'bitbucket-server', 'bitbucket-cloud', 'generic-git-host', 'azuredevops'); + +-- AlterTable - Convert existing column to enum type without dropping data +ALTER TABLE "Repo" + ALTER COLUMN "external_codeHostType" TYPE "CodeHostType" + USING "external_codeHostType"::text::"CodeHostType"; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index 93adb7171..313de6213 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -29,6 +29,21 @@ enum ChatVisibility { PUBLIC } +/// @note: The @map annotation is required to maintain backwards compatibility +/// with the existing database. +/// @note: In the generated client, these mapped values will be in pascalCase. +/// This behaviour will change in prisma v7. See: https://github.com/prisma/prisma/issues/8446#issuecomment-3356119713 +enum CodeHostType { + github + gitlab + gitea + gerrit + bitbucketServer @map("bitbucket-server") + bitbucketCloud @map("bitbucket-cloud") + genericGitHost @map("generic-git-host") + azuredevops +} + model Repo { id Int @id @default(autoincrement()) name String /// Full repo name, including the vcs hostname (ex. github.com/sourcebot-dev/sourcebot) @@ -53,7 +68,7 @@ model Repo { indexedCommitHash String? /// The commit hash of the last indexed commit (on HEAD). external_id String /// The id of the repo in the external service - external_codeHostType String /// The type of the external service (e.g., github, gitlab, etc.) + external_codeHostType CodeHostType /// The type of the external service (e.g., github, gitlab, etc.) external_codeHostUrl String /// The base url of the external service (e.g., https://github.com) org Org @relation(fields: [orgId], references: [id], onDelete: Cascade) @@ -125,6 +140,18 @@ model SearchContext { @@unique([name, orgId]) } +/// Matches the union of `type` fields in the schema. +/// @see: schemas/v3/connection.type.ts +enum ConnectionType { + github + gitlab + gitea + gerrit + bitbucket + azuredevops + git +} + model Connection { id Int @id @default(autoincrement()) name String @@ -135,7 +162,7 @@ model Connection { repos RepoToConnection[] // The type of connection (e.g., github, gitlab, etc.) - connectionType String + connectionType ConnectionType syncJobs ConnectionSyncJob[] /// When the connection was last synced successfully. diff --git a/packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx b/packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx index 01a84447e..b38d140b3 100644 --- a/packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx +++ b/packages/web/src/app/[domain]/browse/[...path]/components/codePreviewPanel.tsx @@ -52,7 +52,7 @@ export const CodePreviewPanel = async ({ path, repoName, revisionName }: CodePre branchDisplayName={revisionName} /> - {(fileWebUrl && codeHostInfo) && ( + {fileWebUrl && ( = (previous: T) => T; export type QuickAction = { diff --git a/packages/web/src/app/[domain]/components/importSecretDialog.tsx b/packages/web/src/app/[domain]/components/importSecretDialog.tsx index b67fea7a4..23d8aefea 100644 --- a/packages/web/src/app/[domain]/components/importSecretDialog.tsx +++ b/packages/web/src/app/[domain]/components/importSecretDialog.tsx @@ -9,10 +9,11 @@ import { Input } from "@/components/ui/input"; import { Separator } from "@/components/ui/separator"; import useCaptureEvent from "@/hooks/useCaptureEvent"; import { useDomain } from "@/hooks/useDomain"; -import { CodeHostType, isServiceError } from "@/lib/utils"; +import { isServiceError } from "@/lib/utils"; import githubPatCreation from "@/public/github_pat_creation.png"; import gitlabPatCreation from "@/public/gitlab_pat_creation.png"; import giteaPatCreation from "@/public/gitea_pat_creation.png"; +import { CodeHostType } from "@sourcebot/db"; import { zodResolver } from "@hookform/resolvers/zod"; import { Eye, EyeOff, Loader2 } from "lucide-react"; import Image from "next/image"; @@ -88,9 +89,9 @@ export const ImportSecretDialog = ({ open, onOpenChange, onSecretCreated, codeHo return ; case 'gitlab': return ; - case 'bitbucket-cloud': + case 'bitbucketCloud': return ; - case 'bitbucket-server': + case 'bitbucketServer': return ; case 'gitea': return ; diff --git a/packages/web/src/app/[domain]/components/navigationMenu/progressIndicator.tsx b/packages/web/src/app/[domain]/components/navigationMenu/progressIndicator.tsx index 2584f11c1..71e8285a0 100644 --- a/packages/web/src/app/[domain]/components/navigationMenu/progressIndicator.tsx +++ b/packages/web/src/app/[domain]/components/navigationMenu/progressIndicator.tsx @@ -10,7 +10,7 @@ import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; import { RepositoryQuery } from "@/lib/types"; import { getCodeHostInfoForRepo, getShortenedNumberDisplayString } from "@/lib/utils"; import clsx from "clsx"; -import { FileIcon, Loader2Icon, RefreshCwIcon } from "lucide-react"; +import { Loader2Icon, RefreshCwIcon } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/navigation"; @@ -90,23 +90,14 @@ const RepoItem = ({ repo }: { repo: RepositoryQuery }) => { webUrl: repo.webUrl, }); - if (info) { - return { - repoIcon: {info.codeHostName}, - displayName: info.displayName, - } - } - return { - repoIcon: , - displayName: repo.repoName, + repoIcon: {info.codeHostName}, + displayName: info.displayName, } - - }, [repo.repoName, repo.codeHostType, repo.repoDisplayName, repo.webUrl]); diff --git a/packages/web/src/app/[domain]/components/pathHeader.tsx b/packages/web/src/app/[domain]/components/pathHeader.tsx index 11b5bf1d8..d65d2c35c 100644 --- a/packages/web/src/app/[domain]/components/pathHeader.tsx +++ b/packages/web/src/app/[domain]/components/pathHeader.tsx @@ -1,7 +1,6 @@ 'use client'; import { cn, getCodeHostInfoForRepo } from "@/lib/utils"; -import { LaptopIcon } from "@radix-ui/react-icons"; import Image from "next/image"; import { getBrowsePath } from "../browse/hooks/utils"; import { ChevronRight, MoreHorizontal } from "lucide-react"; @@ -17,6 +16,7 @@ import { VscodeFileIcon } from "@/app/components/vscodeFileIcon"; import { CopyIconButton } from "./copyIconButton"; import Link from "next/link"; import { useDomain } from "@/hooks/useDomain"; +import { CodeHostType } from "@sourcebot/db"; interface FileHeaderProps { path: string; @@ -27,7 +27,7 @@ interface FileHeaderProps { pathType?: 'blob' | 'tree'; repo: { name: string; - codeHostType: string; + codeHostType: CodeHostType; displayName?: string; webUrl?: string; }, @@ -202,17 +202,13 @@ export const PathHeader = ({
{isCodeHostIconVisible && ( <> - {info?.icon ? ( - - {info.codeHostName} - - ) : ( - - )} + + {info.codeHostName} + )} diff --git a/packages/web/src/app/[domain]/components/repositoryCarousel.tsx b/packages/web/src/app/[domain]/components/repositoryCarousel.tsx index a9d1239f3..f5576abac 100644 --- a/packages/web/src/app/[domain]/components/repositoryCarousel.tsx +++ b/packages/web/src/app/[domain]/components/repositoryCarousel.tsx @@ -8,7 +8,6 @@ import { import { captureEvent } from "@/hooks/useCaptureEvent"; import { RepositoryQuery } from "@/lib/types"; import { getCodeHostInfoForRepo } from "@/lib/utils"; -import { FileIcon } from "@radix-ui/react-icons"; import clsx from "clsx"; import Autoscroll from "embla-carousel-auto-scroll"; import Image from "next/image"; @@ -121,20 +120,13 @@ const RepositoryBadge = ({ webUrl: repo.webUrl, }); - if (info) { - return { - repoIcon: {info.codeHostName}, - displayName: info.displayName, - } - } - return { - repoIcon: , - displayName: repo.repoName, + repoIcon: {info.codeHostName}, + displayName: info.displayName, } })(); diff --git a/packages/web/src/app/[domain]/repos/[id]/page.tsx b/packages/web/src/app/[domain]/repos/[id]/page.tsx index db14e50c1..a3255c040 100644 --- a/packages/web/src/app/[domain]/repos/[id]/page.tsx +++ b/packages/web/src/app/[domain]/repos/[id]/page.tsx @@ -65,7 +65,7 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:

{repo.displayName || repo.name}

{repo.name}

- {(codeHostInfo && codeHostInfo.repoLink) && ( + {codeHostInfo.repoLink && (