From eb459b5afaf42621a6cb2e698715fa017e26e5d7 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 9 Oct 2026 14:50:01 -0700 Subject: [PATCH] refactor(source-control): GitLab lives in @t3tools/source-control-gitlab (#17594) Co-authored-by: Claude Opus 5.5 --- apps/server/package.json | 2 + apps/server/scripts/evaluate-thread-titles.ts | 2 - apps/server/src/git/GitManager.test.ts | 22 +++++--- .../PullRequestProviderRateLimit.test.ts | 4 +- .../PullRequestProviderRegistry.ts | 5 -- apps/server/src/server.ts | 2 - .../SourceControlDiscovery.test.ts | 4 +- .../SourceControlProviderRegistry.test.ts | 4 +- .../SourceControlProviderRegistry.ts | 7 --- .../src/sourceControl/builtInDrivers.ts | 6 +- apps/server/src/ws.ts | 2 - docs/internals/pull-request-file-revisions.md | 4 +- package.json | 2 +- packages/source-control-gitlab/package.json | 55 +++++++++++++++++++ .../src/server}/GitLabCli.test.ts | 15 ++--- .../src/server}/GitLabCli.ts | 8 +-- .../src/server}/GitLabPullRequestCli.test.ts | 2 +- .../src/server}/GitLabPullRequestCli.ts | 4 +- .../server}/GitLabPullRequestProvider.test.ts | 0 .../src/server}/GitLabPullRequestProvider.ts | 0 .../GitLabSourceControlProvider.test.ts | 0 .../server}/GitLabSourceControlProvider.ts | 0 .../src/server/driver.ts | 19 +++++++ .../src/server}/gitLabAuthStatus.ts | 0 .../server}/gitLabMergeRequestJson.test.ts | 0 .../src/server}/gitLabMergeRequestJson.ts | 0 .../src/server}/gitLabMergeRequests.ts | 0 packages/source-control-gitlab/tsconfig.json | 7 +++ pnpm-lock.yaml | 34 ++++++++++++ scripts/release-smoke.ts | 1 + 30 files changed, 159 insertions(+), 52 deletions(-) create mode 100644 packages/source-control-gitlab/package.json rename {apps/server/src/sourceControl => packages/source-control-gitlab/src/server}/GitLabCli.test.ts (95%) rename {apps/server/src/sourceControl => packages/source-control-gitlab/src/server}/GitLabCli.ts (98%) rename {apps/server/src/pullRequest => packages/source-control-gitlab/src/server}/GitLabPullRequestCli.test.ts (99%) rename {apps/server/src/pullRequest => packages/source-control-gitlab/src/server}/GitLabPullRequestCli.ts (99%) rename {apps/server/src/pullRequest => packages/source-control-gitlab/src/server}/GitLabPullRequestProvider.test.ts (100%) rename {apps/server/src/pullRequest => packages/source-control-gitlab/src/server}/GitLabPullRequestProvider.ts (100%) rename {apps/server/src/sourceControl => packages/source-control-gitlab/src/server}/GitLabSourceControlProvider.test.ts (100%) rename {apps/server/src/sourceControl => packages/source-control-gitlab/src/server}/GitLabSourceControlProvider.ts (100%) create mode 100644 packages/source-control-gitlab/src/server/driver.ts rename {apps/server/src/sourceControl => packages/source-control-gitlab/src/server}/gitLabAuthStatus.ts (100%) rename {apps/server/src/pullRequest => packages/source-control-gitlab/src/server}/gitLabMergeRequestJson.test.ts (100%) rename {apps/server/src/pullRequest => packages/source-control-gitlab/src/server}/gitLabMergeRequestJson.ts (100%) rename {apps/server/src/sourceControl => packages/source-control-gitlab/src/server}/gitLabMergeRequests.ts (100%) create mode 100644 packages/source-control-gitlab/tsconfig.json diff --git a/apps/server/package.json b/apps/server/package.json index 232a99960f96ebd4dc971f5bfc63743a9f66a624..a246302618a3ace14fb157ebfb4d232a64758321 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -48,6 +48,7 @@ "@t3tools/source-control-azure-devops": "workspace:*", "@t3tools/source-control-core": "workspace:*", "@t3tools/source-control-forgejo": "workspace:*", + "@t3tools/source-control-gitlab": "workspace:*", "effect": "catalog:", "jose": "catalog:", "node-pty": "^1.2.0-beta.15", @@ -64,6 +65,7 @@ "@t3tools/contracts": "workspace:*", "@t3tools/provider-testing": "workspace:*", "@t3tools/shared": "workspace:*", + "@t3tools/source-control-testing": "workspace:*", "@t3tools/ssh": "workspace:*", "@t3tools/tailscale": "workspace:*", "@t3tools/web": "workspace:*", diff --git a/apps/server/scripts/evaluate-thread-titles.ts b/apps/server/scripts/evaluate-thread-titles.ts index 92313a0869c7019f0d33393481a3fc21e6191cc2..0b3fb1393239b5b72b09be9e6866ae2399331cb0 100644 --- a/apps/server/scripts/evaluate-thread-titles.ts +++ b/apps/server/scripts/evaluate-thread-titles.ts @@ -24,7 +24,6 @@ import { import * as ThreadTitleLinks from "../src/textGeneration/ThreadTitleLinks.ts"; import * as SourceControlProviderRegistry from "../src/sourceControl/SourceControlProviderRegistry.ts"; import * as GitHubApi from "../src/sourceControl/GitHubApi.ts"; -import * as GitLabCli from "../src/sourceControl/GitLabCli.ts"; import * as SourceControlBuiltInDrivers from "../src/sourceControl/builtInDrivers.ts"; import * as BitbucketApi from "../src/sourceControl/BitbucketApi.ts"; import * as ServerSettings from "../src/serverSettings.ts"; @@ -152,7 +151,6 @@ await Effect.runPromise( Layer.provide( Layer.mergeAll( GitHubApi.layerWithDependencies, - GitLabCli.layer, SourceControlBuiltInDrivers.layer, // No saved credentials here; Bitbucket falls back to T3CODE_BITBUCKET_* variables. BitbucketApi.layer, diff --git a/apps/server/src/git/GitManager.test.ts b/apps/server/src/git/GitManager.test.ts index 9df266d56c8f58675cd310b246b4e38057c86879..92b7fcd607fc1046deb875c7b99f6c3779f71837 100644 --- a/apps/server/src/git/GitManager.test.ts +++ b/apps/server/src/git/GitManager.test.ts @@ -44,7 +44,9 @@ import { } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; import { decodeGitHubPullRequestListJson } from "../sourceControl/gitHubPullRequests.ts"; -import * as GitLabCli from "../sourceControl/GitLabCli.ts"; +import * as GitLabCli from "@t3tools/source-control-gitlab/server/GitLabCli"; +import type * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost"; +import * as TestSourceControlHost from "@t3tools/source-control-testing/TestSourceControlHost"; import * as TextGeneration from "../textGeneration/TextGeneration.ts"; import * as GitVcsDriver from "../vcs/GitVcsDriver.ts"; import * as VcsProcess from "../vcs/VcsProcess.ts"; @@ -53,7 +55,7 @@ import * as VcsProjectConfig from "../vcs/VcsProjectConfig.ts"; import * as VcsStatusBroadcaster from "../vcs/VcsStatusBroadcaster.ts"; import * as BackgroundPolicy from "../background/BackgroundPolicy.ts"; import * as GitWorkflowService from "./GitWorkflowService.ts"; -import * as GitLabSourceControlProvider from "../sourceControl/GitLabSourceControlProvider.ts"; +import * as GitLabSourceControlProvider from "@t3tools/source-control-gitlab/server/GitLabSourceControlProvider"; import { ForgejoPullRequestSchema, toForgejoChangeRequest, @@ -2108,17 +2110,19 @@ it.layer(layerGitManagerTest)("GitManager", (it) => { source_project: { path_with_namespace: "Group/Subgroup/Fork" }, }, ]); - const calls: VcsProcess.VcsProcessInput[] = []; + const calls: SourceControlHost.SourceControlProcessInput[] = []; const provider = yield* GitLabSourceControlProvider.make.pipe( Effect.provide( GitLabCli.layer.pipe( Layer.provide( - Layer.mock(VcsProcess.VcsProcess)({ - run: (input) => - Effect.sync(() => { - calls.push(input); - return fakeGhOutput(output); - }), + TestSourceControlHost.layer({ + process: { + run: (input) => + Effect.sync(() => { + calls.push(input); + return fakeGhOutput(output); + }), + }, }), ), ), diff --git a/apps/server/src/pullRequest/PullRequestProviderRateLimit.test.ts b/apps/server/src/pullRequest/PullRequestProviderRateLimit.test.ts index 38f58735398001c68af44c7abecceb9e5c1e6a56..b26bbe8ae9bad5f5bdd5be773baf27689df1728f 100644 --- a/apps/server/src/pullRequest/PullRequestProviderRateLimit.test.ts +++ b/apps/server/src/pullRequest/PullRequestProviderRateLimit.test.ts @@ -4,11 +4,11 @@ import * as AzureDevOpsCli from "@t3tools/source-control-azure-devops/server/Azu import * as BitbucketApi from "../sourceControl/BitbucketApi.ts"; import * as GitHubApi from "../sourceControl/GitHubApi.ts"; import * as SourceControlRateLimit from "@t3tools/source-control-core/server/SourceControlRateLimit"; -import * as GitLabCli from "../sourceControl/GitLabCli.ts"; +import * as GitLabCli from "@t3tools/source-control-gitlab/server/GitLabCli"; import { azureDevOpsProviderFailure } from "@t3tools/source-control-azure-devops/server/AzureDevOpsPullRequestProvider"; import { bitbucketProviderFailure } from "./BitbucketPullRequestProvider.ts"; import { gitHubProviderFailure } from "./GitHubPullRequestProvider.ts"; -import { gitLabProviderFailure } from "./GitLabPullRequestProvider.ts"; +import { gitLabProviderFailure } from "@t3tools/source-control-gitlab/server/GitLabPullRequestProvider"; const cause = new Error("redacted provider failure"); diff --git a/apps/server/src/pullRequest/PullRequestProviderRegistry.ts b/apps/server/src/pullRequest/PullRequestProviderRegistry.ts index 009d3d3f8b4f1c99c459f135b03f46efbc0de980..74d7dc47174848c1568e2fd95e37182bb77d8c80 100644 --- a/apps/server/src/pullRequest/PullRequestProviderRegistry.ts +++ b/apps/server/src/pullRequest/PullRequestProviderRegistry.ts @@ -5,13 +5,10 @@ import type { SourceControlProviderKind } from "@t3tools/contracts"; import * as BitbucketApi from "../sourceControl/BitbucketApi.ts"; import * as GitHubApi from "../sourceControl/GitHubApi.ts"; -import * as GitLabCli from "../sourceControl/GitLabCli.ts"; import * as BitbucketPullRequestApi from "./BitbucketPullRequestApi.ts"; import * as BitbucketPullRequestProvider from "./BitbucketPullRequestProvider.ts"; import * as GitHubPullRequestApi from "./GitHubPullRequestApi.ts"; import * as GitHubPullRequestProvider from "./GitHubPullRequestProvider.ts"; -import * as GitLabPullRequestCli from "./GitLabPullRequestCli.ts"; -import * as GitLabPullRequestProvider from "./GitLabPullRequestProvider.ts"; import * as BuiltInDrivers from "../sourceControl/builtInDrivers.ts"; import type { PullRequestProviderApi } from "@t3tools/source-control-core/server/PullRequestProvider"; @@ -44,7 +41,6 @@ export function fromProviders( export const make = Effect.gen(function* () { const providers = yield* Effect.all([ GitHubPullRequestProvider.make, - GitLabPullRequestProvider.make, BitbucketPullRequestProvider.make, ]); const drivers = yield* Effect.forEach(BuiltInDrivers.BUILT_IN_SOURCE_CONTROL_DRIVERS, (driver) => @@ -65,7 +61,6 @@ export const layer = Layer.effect(PullRequestProviderRegistry, make).pipe( ), ), ), - Layer.provide(GitLabPullRequestCli.layer.pipe(Layer.provide(GitLabCli.layer))), Layer.provide(BuiltInDrivers.layer), Layer.provide(BitbucketPullRequestApi.layer.pipe(Layer.provide(BitbucketApi.layer))), ); diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts index 82c5de077ef75e1411f17d5ba5927db26ea6c02f..8ea3b5cda1981b9e190c440df1927dd1bc05d869 100644 --- a/apps/server/src/server.ts +++ b/apps/server/src/server.ts @@ -54,7 +54,6 @@ import * as CheckpointDiffQuery from "./checkpointing/CheckpointDiffQuery.ts"; import * as CheckpointStore from "./checkpointing/CheckpointStore.ts"; import * as BitbucketApi from "./sourceControl/BitbucketApi.ts"; import * as GitHubApi from "./sourceControl/GitHubApi.ts"; -import * as GitLabCli from "./sourceControl/GitLabCli.ts"; import * as ForgejoCli from "@t3tools/source-control-forgejo/server/ForgejoCli"; import * as SourceControlBuiltInDrivers from "./sourceControl/builtInDrivers.ts"; import * as TextGeneration from "./textGeneration/TextGeneration.ts"; @@ -302,7 +301,6 @@ const layerSourceControlProviderRegistry = SourceControlProviderRegistry.layer.p Layer.mergeAll( BitbucketApi.layer, GitHubApi.layerWithDependencies, - GitLabCli.layer, SourceControlBuiltInDrivers.layer, ), ), diff --git a/apps/server/src/sourceControl/SourceControlDiscovery.test.ts b/apps/server/src/sourceControl/SourceControlDiscovery.test.ts index e818a92746359495c7b54a31c000d1dcfa01f266..c87d731953da9812cd4360ae850deadc347df3c8 100644 --- a/apps/server/src/sourceControl/SourceControlDiscovery.test.ts +++ b/apps/server/src/sourceControl/SourceControlDiscovery.test.ts @@ -20,7 +20,8 @@ import * as AzureDevOpsCli from "@t3tools/source-control-azure-devops/server/Azu import * as AzureDevOpsPullRequestCli from "@t3tools/source-control-azure-devops/server/AzureDevOpsPullRequestCli"; import * as BitbucketApi from "./BitbucketApi.ts"; import * as GitHubApi from "./GitHubApi.ts"; -import * as GitLabCli from "./GitLabCli.ts"; +import * as GitLabCli from "@t3tools/source-control-gitlab/server/GitLabCli"; +import * as GitLabPullRequestCli from "@t3tools/source-control-gitlab/server/GitLabPullRequestCli"; import * as ForgejoCli from "@t3tools/source-control-forgejo/server/ForgejoCli"; import * as ForgejoSourceControlProvider from "@t3tools/source-control-forgejo/server/ForgejoSourceControlProvider"; import * as ForgejoPullRequestProvider from "@t3tools/source-control-forgejo/server/ForgejoPullRequestProvider"; @@ -46,6 +47,7 @@ const layerSourceControlProviderRegistryTest = (input: { Layer.mock(GitHubApi.GitHubApi)({}), Layer.mock(GitVcsDriver.GitVcsDriver)({}), Layer.mock(GitLabCli.GitLabCli)({}), + Layer.mock(GitLabPullRequestCli.GitLabPullRequestCli)({}), Layer.mock(ForgejoCli.ForgejoCli)({ listLogins: () => Effect.succeed([]) }), Layer.mock(VcsDriverRegistry.VcsDriverRegistry)({}), Layer.mock(VcsProcess.VcsProcess)(input.process), diff --git a/apps/server/src/sourceControl/SourceControlProviderRegistry.test.ts b/apps/server/src/sourceControl/SourceControlProviderRegistry.test.ts index 5f48bae18588eea281644217c774312612ce715c..582848b38a4b65a3a52bcba421ccc4f2a7e30bf5 100644 --- a/apps/server/src/sourceControl/SourceControlProviderRegistry.test.ts +++ b/apps/server/src/sourceControl/SourceControlProviderRegistry.test.ts @@ -19,7 +19,8 @@ import * as BitbucketApi from "./BitbucketApi.ts"; import * as GitVcsDriver from "../vcs/GitVcsDriver.ts"; import * as GitHubApi from "./GitHubApi.ts"; import * as GitHubCredentials from "./GitHubCredentials.ts"; -import * as GitLabCli from "./GitLabCli.ts"; +import * as GitLabCli from "@t3tools/source-control-gitlab/server/GitLabCli"; +import * as GitLabPullRequestCli from "@t3tools/source-control-gitlab/server/GitLabPullRequestCli"; import * as ForgejoCli from "@t3tools/source-control-forgejo/server/ForgejoCli"; import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts"; import * as ServerSourceControlHost from "./ServerSourceControlHost.ts"; @@ -114,6 +115,7 @@ function makeRegistry(input: { }), Layer.mock(GitVcsDriver.GitVcsDriver)({}), Layer.mock(GitLabCli.GitLabCli)(input.gitlab ?? {}), + Layer.mock(GitLabPullRequestCli.GitLabPullRequestCli)({}), Layer.mock(ForgejoCli.ForgejoCli)({ listLogins: () => Effect.succeed([]) }), ServerConfig.layerTest(process.cwd(), { prefix: "t3-source-control-registry-test-", diff --git a/apps/server/src/sourceControl/SourceControlProviderRegistry.ts b/apps/server/src/sourceControl/SourceControlProviderRegistry.ts index 948d583296faf8974a1994d34543e8d84c3893db..9eeae3d935f7a80ac606a0005a594b12f593290e 100644 --- a/apps/server/src/sourceControl/SourceControlProviderRegistry.ts +++ b/apps/server/src/sourceControl/SourceControlProviderRegistry.ts @@ -13,7 +13,6 @@ import { detectSourceControlProviderFromRemoteUrl } from "@t3tools/shared/source import * as BitbucketSourceControlProvider from "./BitbucketSourceControlProvider.ts"; import * as GitHubSourceControlProvider from "./GitHubSourceControlProvider.ts"; -import * as GitLabSourceControlProvider from "./GitLabSourceControlProvider.ts"; import * as BuiltInDrivers from "./builtInDrivers.ts"; import * as SourceControlProvider from "@t3tools/source-control-core/server/SourceControlProvider"; import { @@ -306,7 +305,6 @@ export const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWit export const make = Effect.gen(function* () { const github = yield* GitHubSourceControlProvider.make; const githubDiscovery = yield* GitHubSourceControlProvider.makeDiscovery; - const gitlab = yield* GitLabSourceControlProvider.make; const bitbucket = yield* BitbucketSourceControlProvider.make; const bitbucketDiscovery = yield* BitbucketSourceControlProvider.makeDiscovery; const drivers = yield* Effect.forEach(BuiltInDrivers.BUILT_IN_SOURCE_CONTROL_DRIVERS, (driver) => @@ -326,11 +324,6 @@ export const make = Effect.gen(function* () { provider: github, discovery: githubDiscovery, }, - { - kind: "gitlab", - provider: gitlab, - discovery: GitLabSourceControlProvider.discovery, - }, { kind: "bitbucket", provider: bitbucket, diff --git a/apps/server/src/sourceControl/builtInDrivers.ts b/apps/server/src/sourceControl/builtInDrivers.ts index 584bf139c0fb64205d60428c66d987e18e1ea0a1..83ee1d35e8f5f91a9a897e04a827f1ada4dca455 100644 --- a/apps/server/src/sourceControl/builtInDrivers.ts +++ b/apps/server/src/sourceControl/builtInDrivers.ts @@ -12,12 +12,15 @@ import * as AzureDevOpsPullRequestCli from "@t3tools/source-control-azure-devops import * as AzureDevOpsDriver from "@t3tools/source-control-azure-devops/server/driver"; import * as ForgejoCli from "@t3tools/source-control-forgejo/server/ForgejoCli"; import * as ForgejoDriver from "@t3tools/source-control-forgejo/server/driver"; +import * as GitLabCli from "@t3tools/source-control-gitlab/server/GitLabCli"; +import * as GitLabPullRequestCli from "@t3tools/source-control-gitlab/server/GitLabPullRequestCli"; +import * as GitLabDriver from "@t3tools/source-control-gitlab/server/driver"; import type { SourceControlDriver } from "@t3tools/source-control-core/server/driver"; import * as Layer from "effect/Layer"; import * as ServerSourceControlHost from "./ServerSourceControlHost.ts"; -const drivers = [AzureDevOpsDriver.driver, ForgejoDriver.driver]; +const drivers = [GitLabDriver.driver, AzureDevOpsDriver.driver, ForgejoDriver.driver]; /** Every service a built-in driver's `make` needs; the server's layers must provide them all. */ export type BuiltInSourceControlDriversEnv = @@ -31,4 +34,5 @@ export const BUILT_IN_SOURCE_CONTROL_DRIVERS: ReadonlyArray< export const layer = Layer.mergeAll( AzureDevOpsPullRequestCli.layer.pipe(Layer.provideMerge(AzureDevOpsCli.layer)), ForgejoCli.layer, + GitLabPullRequestCli.layer.pipe(Layer.provideMerge(GitLabCli.layer)), ).pipe(Layer.provideMerge(ServerSourceControlHost.layer)); diff --git a/apps/server/src/ws.ts b/apps/server/src/ws.ts index 899f021eb937838dd213e273d8a58592fb3ec699..19ed2600ba5e739daf3375cf1234363b77484c93 100644 --- a/apps/server/src/ws.ts +++ b/apps/server/src/ws.ts @@ -231,7 +231,6 @@ import * as SourceControlDiscovery from "./sourceControl/SourceControlDiscovery. import * as SourceControlRepositoryService from "./sourceControl/SourceControlRepositoryService.ts"; import * as BitbucketApi from "./sourceControl/BitbucketApi.ts"; import * as GitHubApi from "./sourceControl/GitHubApi.ts"; -import * as GitLabCli from "./sourceControl/GitLabCli.ts"; import * as SourceControlBuiltInDrivers from "./sourceControl/builtInDrivers.ts"; import * as SourceControlProviderRegistry from "./sourceControl/SourceControlProviderRegistry.ts"; import * as GitVcsDriver from "./vcs/GitVcsDriver.ts"; @@ -3205,7 +3204,6 @@ export const layer = Layer.unwrap( Layer.mergeAll( BitbucketApi.layer, GitHubApi.layerWithDependencies, - GitLabCli.layer, SourceControlBuiltInDrivers.layer, ), ), diff --git a/docs/internals/pull-request-file-revisions.md b/docs/internals/pull-request-file-revisions.md index ceb80de8efe03f5d6e519b0645502e320cfd6d1a..8fd0dfdb69db12746bbcab551fee15af12369540 100644 --- a/docs/internals/pull-request-file-revisions.md +++ b/docs/internals/pull-request-file-revisions.md @@ -7,7 +7,7 @@ one. No type distinguishes those meanings and no single file states the whole pa this page is for. The failure is on record rather than hypothetical. The interface doc above -[GitLab's `getFileRevisions`](../../apps/server/src/pullRequest/GitLabPullRequestCli.ts) once said +[GitLab's `getFileRevisions`](../../packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts) once said the opposite of the code beneath it, because it described a missing path the way the layer below means it. Anything written against that reading would treat a version the host declined to give as a file the change request deleted, which reports every file a reader has cleared as changed across @@ -30,7 +30,7 @@ What "never got to look at" is belongs to the host, and the contract cannot know - [Bitbucket](../../apps/server/src/pullRequest/BitbucketPullRequestApi.ts) reads them off the pull request's own patch, the only place it states a file's version, so a patch cut short at the byte ceiling leaves the paths past the cut out. -- [GitLab](../../apps/server/src/pullRequest/GitLabPullRequestCli.ts) asks in batches, so a batch +- [GitLab](../../packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts) asks in batches, so a batch it could not read leaves that batch's paths out. Those three facts stay with their providers. The contract states only that absence means the read diff --git a/package.json b/package.json index bb1d183efb891058eab579b338e39679d10eeecc..4e0ba35ecc7e09b2990be8fe7e7ea12d0de6a349 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "tc": "vp run -r --concurrency-limit 2 typecheck", "lint": "vp lint --report-unused-disable-directives", "knip": "knip --preprocessor ./scripts/knip-schemas.ts", - "knip:check": "knip --include files,dependencies --no-config-hints && knip --workspace apps/server --workspace apps/desktop --workspace apps/web --workspace packages/client-runtime --workspace packages/contracts --workspace packages/effect-acp --workspace packages/effect-codex-app-server --workspace packages/shared --workspace packages/ssh --workspace packages/tailscale --workspace packages/provider-core --workspace packages/provider-acp --workspace packages/provider-acp-registry --workspace packages/provider-testing --workspace packages/provider-pi --workspace packages/provider-muse --workspace packages/provider-opencode --workspace packages/provider-cursor --workspace packages/provider-grok --workspace packages/source-control-core --workspace packages/source-control-azure-devops --workspace packages/source-control-forgejo --workspace packages/source-control-testing --exports --preprocessor ./scripts/knip-schemas.ts --no-config-hints", + "knip:check": "knip --include files,dependencies --no-config-hints && knip --workspace apps/server --workspace apps/desktop --workspace apps/web --workspace packages/client-runtime --workspace packages/contracts --workspace packages/effect-acp --workspace packages/effect-codex-app-server --workspace packages/shared --workspace packages/ssh --workspace packages/tailscale --workspace packages/provider-core --workspace packages/provider-acp --workspace packages/provider-acp-registry --workspace packages/provider-testing --workspace packages/provider-pi --workspace packages/provider-muse --workspace packages/provider-opencode --workspace packages/provider-cursor --workspace packages/provider-grok --workspace packages/source-control-core --workspace packages/source-control-azure-devops --workspace packages/source-control-forgejo --workspace packages/source-control-gitlab --workspace packages/source-control-testing --exports --preprocessor ./scripts/knip-schemas.ts --no-config-hints", "knip:production": "knip --production --preprocessor ./scripts/knip-schemas.ts", "lint:mobile": "node scripts/mobile-native-static-check.ts", "test": "vp run -r test", diff --git a/packages/source-control-gitlab/package.json b/packages/source-control-gitlab/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6b99c878ccb83317db3948096ccb117a308765df --- /dev/null +++ b/packages/source-control-gitlab/package.json @@ -0,0 +1,55 @@ +{ + "name": "@t3tools/source-control-gitlab", + "private": true, + "type": "module", + "exports": { + "./server/driver": { + "types": "./src/server/driver.ts", + "import": "./src/server/driver.ts" + }, + "./server/gitLabAuthStatus": { + "types": "./src/server/gitLabAuthStatus.ts", + "import": "./src/server/gitLabAuthStatus.ts" + }, + "./server/GitLabCli": { + "types": "./src/server/GitLabCli.ts", + "import": "./src/server/GitLabCli.ts" + }, + "./server/gitLabMergeRequestJson": { + "types": "./src/server/gitLabMergeRequestJson.ts", + "import": "./src/server/gitLabMergeRequestJson.ts" + }, + "./server/gitLabMergeRequests": { + "types": "./src/server/gitLabMergeRequests.ts", + "import": "./src/server/gitLabMergeRequests.ts" + }, + "./server/GitLabPullRequestCli": { + "types": "./src/server/GitLabPullRequestCli.ts", + "import": "./src/server/GitLabPullRequestCli.ts" + }, + "./server/GitLabPullRequestProvider": { + "types": "./src/server/GitLabPullRequestProvider.ts", + "import": "./src/server/GitLabPullRequestProvider.ts" + }, + "./server/GitLabSourceControlProvider": { + "types": "./src/server/GitLabSourceControlProvider.ts", + "import": "./src/server/GitLabSourceControlProvider.ts" + } + }, + "scripts": { + "typecheck": "tsc --noEmit", + "test": "vp test run --config ../../vite.config.ts --dir ." + }, + "dependencies": { + "@t3tools/contracts": "workspace:*", + "@t3tools/shared": "workspace:*", + "@t3tools/source-control-core": "workspace:*", + "effect": "catalog:" + }, + "devDependencies": { + "@effect/vitest": "catalog:", + "@t3tools/source-control-testing": "workspace:*", + "@types/node": "catalog:", + "vite-plus": "catalog:" + } +} diff --git a/apps/server/src/sourceControl/GitLabCli.test.ts b/packages/source-control-gitlab/src/server/GitLabCli.test.ts similarity index 95% rename from apps/server/src/sourceControl/GitLabCli.test.ts rename to packages/source-control-gitlab/src/server/GitLabCli.test.ts index 5a10f13b8f8f4d879734e4bef41000b0747458d2..2756460f78f5923cdfac8c5c442fc1d379df9a64 100644 --- a/apps/server/src/sourceControl/GitLabCli.test.ts +++ b/packages/source-control-gitlab/src/server/GitLabCli.test.ts @@ -5,21 +5,16 @@ import { ChildProcessSpawner } from "effect/process"; import { VcsProcessExitError } from "@t3tools/contracts"; -import * as VcsProcess from "../vcs/VcsProcess.ts"; +import type * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost"; +import * as TestSourceControlHost from "@t3tools/source-control-testing/TestSourceControlHost"; import * as GitLabCli from "./GitLabCli.ts"; -const mockedRun = vi.fn(); +const mockedRun = vi.fn(); const layer = it.layer( - GitLabCli.layer.pipe( - Layer.provide( - Layer.mock(VcsProcess.VcsProcess)({ - run: mockedRun, - }), - ), - ), + GitLabCli.layer.pipe(Layer.provide(TestSourceControlHost.layer({ process: { run: mockedRun } }))), ); -function processOutput(stdout: string): VcsProcess.VcsProcessOutput { +function processOutput(stdout: string): SourceControlHost.SourceControlProcessOutput { return { exitCode: ChildProcessSpawner.ExitCode(0), stdout, diff --git a/apps/server/src/sourceControl/GitLabCli.ts b/packages/source-control-gitlab/src/server/GitLabCli.ts similarity index 98% rename from apps/server/src/sourceControl/GitLabCli.ts rename to packages/source-control-gitlab/src/server/GitLabCli.ts index 2ec69a527fedffa9f1f78dd0cfa74a8a947992d1..6845ee7710013017e8b1edd580a085df55484f8b 100644 --- a/apps/server/src/sourceControl/GitLabCli.ts +++ b/packages/source-control-gitlab/src/server/GitLabCli.ts @@ -13,7 +13,7 @@ import { type VcsError, } from "@t3tools/contracts"; -import * as VcsProcess from "../vcs/VcsProcess.ts"; +import * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost"; import { decodeGitLabMergeRequestJson, decodeGitLabMergeRequestListJson, @@ -270,7 +270,7 @@ export class GitLabCli extends Context.Service< /** Piped to the child's stdin, for payloads that must never appear in argv. */ readonly stdin?: string; readonly maxOutputBytes?: number; - }) => Effect.Effect; + }) => Effect.Effect; readonly listMergeRequests: (input: { readonly cwd: string; @@ -316,7 +316,7 @@ export class GitLabCli extends Context.Service< readonly force?: boolean; }) => Effect.Effect; } ->()("t3/sourceControl/GitLabCli") {} +>()("@t3tools/source-control-gitlab/server/GitLabCli") {} const RawGitLabRepositoryCloneUrlsSchema = Schema.Struct({ path_with_namespace: TrimmedNonEmptyString, @@ -410,7 +410,7 @@ function parseRepositoryPath(repository: string): { /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { - const process = yield* VcsProcess.VcsProcess; + const { process } = yield* SourceControlHost.SourceControlHost; const run = ( input: Parameters[0], diff --git a/apps/server/src/pullRequest/GitLabPullRequestCli.test.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts similarity index 99% rename from apps/server/src/pullRequest/GitLabPullRequestCli.test.ts rename to packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts index 8fb1334de364462999a163d35e73b97f41adc3ab..b4546162f30ca27968c453987de0df820762c4b9 100644 --- a/apps/server/src/pullRequest/GitLabPullRequestCli.test.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.test.ts @@ -3,7 +3,7 @@ import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import { ChildProcessSpawner } from "effect/process"; -import * as GitLabCli from "../sourceControl/GitLabCli.ts"; +import * as GitLabCli from "./GitLabCli.ts"; import * as GitLabPullRequestCli from "./GitLabPullRequestCli.ts"; const mockedExecute = vi.fn(); diff --git a/apps/server/src/pullRequest/GitLabPullRequestCli.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts similarity index 99% rename from apps/server/src/pullRequest/GitLabPullRequestCli.ts rename to packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts index 933e6874218737dae99bb852194175a524be8326..643d130c85bc8a35410eec4eadbdb98775c95f4c 100644 --- a/apps/server/src/pullRequest/GitLabPullRequestCli.ts +++ b/packages/source-control-gitlab/src/server/GitLabPullRequestCli.ts @@ -20,7 +20,7 @@ import type { PullRequestReviewerCandidateList, } from "@t3tools/contracts"; -import * as GitLabCli from "../sourceControl/GitLabCli.ts"; +import * as GitLabCli from "./GitLabCli.ts"; import { AWARD_EMOJI_GRAPHQL_QUERY, decodeAwardEmojiJson, @@ -411,7 +411,7 @@ export class GitLabPullRequestCli extends Context.Service< readonly reacted: boolean; }) => Effect.Effect; } ->()("t3/pullRequest/GitLabPullRequestCli") {} +>()("@t3tools/source-control-gitlab/server/GitLabPullRequestCli") {} /** The REST API addresses a project by its URL-encoded full path. */ function projectPath(repository: string): string { diff --git a/apps/server/src/pullRequest/GitLabPullRequestProvider.test.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestProvider.test.ts similarity index 100% rename from apps/server/src/pullRequest/GitLabPullRequestProvider.test.ts rename to packages/source-control-gitlab/src/server/GitLabPullRequestProvider.test.ts diff --git a/apps/server/src/pullRequest/GitLabPullRequestProvider.ts b/packages/source-control-gitlab/src/server/GitLabPullRequestProvider.ts similarity index 100% rename from apps/server/src/pullRequest/GitLabPullRequestProvider.ts rename to packages/source-control-gitlab/src/server/GitLabPullRequestProvider.ts diff --git a/apps/server/src/sourceControl/GitLabSourceControlProvider.test.ts b/packages/source-control-gitlab/src/server/GitLabSourceControlProvider.test.ts similarity index 100% rename from apps/server/src/sourceControl/GitLabSourceControlProvider.test.ts rename to packages/source-control-gitlab/src/server/GitLabSourceControlProvider.test.ts diff --git a/apps/server/src/sourceControl/GitLabSourceControlProvider.ts b/packages/source-control-gitlab/src/server/GitLabSourceControlProvider.ts similarity index 100% rename from apps/server/src/sourceControl/GitLabSourceControlProvider.ts rename to packages/source-control-gitlab/src/server/GitLabSourceControlProvider.ts diff --git a/packages/source-control-gitlab/src/server/driver.ts b/packages/source-control-gitlab/src/server/driver.ts new file mode 100644 index 0000000000000000000000000000000000000000..29327a35019b2b84da2dfb2370daff02436449b7 --- /dev/null +++ b/packages/source-control-gitlab/src/server/driver.ts @@ -0,0 +1,19 @@ +/** + * The GitLab driver: repository operations, discovery, and merge requests through `glab`. + * + * @module source-control-gitlab/server/driver + */ +import { defineSourceControlDriver } from "@t3tools/source-control-core/server/driver"; +import * as Effect from "effect/Effect"; + +import * as GitLabPullRequestProvider from "./GitLabPullRequestProvider.ts"; +import * as GitLabSourceControlProvider from "./GitLabSourceControlProvider.ts"; + +export const driver = defineSourceControlDriver({ + kind: "gitlab", + make: Effect.all({ + sourceControl: GitLabSourceControlProvider.make, + discovery: Effect.succeed(GitLabSourceControlProvider.discovery), + pullRequests: GitLabPullRequestProvider.make, + }), +}); diff --git a/apps/server/src/sourceControl/gitLabAuthStatus.ts b/packages/source-control-gitlab/src/server/gitLabAuthStatus.ts similarity index 100% rename from apps/server/src/sourceControl/gitLabAuthStatus.ts rename to packages/source-control-gitlab/src/server/gitLabAuthStatus.ts diff --git a/apps/server/src/pullRequest/gitLabMergeRequestJson.test.ts b/packages/source-control-gitlab/src/server/gitLabMergeRequestJson.test.ts similarity index 100% rename from apps/server/src/pullRequest/gitLabMergeRequestJson.test.ts rename to packages/source-control-gitlab/src/server/gitLabMergeRequestJson.test.ts diff --git a/apps/server/src/pullRequest/gitLabMergeRequestJson.ts b/packages/source-control-gitlab/src/server/gitLabMergeRequestJson.ts similarity index 100% rename from apps/server/src/pullRequest/gitLabMergeRequestJson.ts rename to packages/source-control-gitlab/src/server/gitLabMergeRequestJson.ts diff --git a/apps/server/src/sourceControl/gitLabMergeRequests.ts b/packages/source-control-gitlab/src/server/gitLabMergeRequests.ts similarity index 100% rename from apps/server/src/sourceControl/gitLabMergeRequests.ts rename to packages/source-control-gitlab/src/server/gitLabMergeRequests.ts diff --git a/packages/source-control-gitlab/tsconfig.json b/packages/source-control-gitlab/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..374bac55202ddcad695ede1c567ec219a61e9c48 --- /dev/null +++ b/packages/source-control-gitlab/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "types": ["node"] + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54036c86d8626778e14492383cd9ff556d2e5a97..13c583be13f07dd763f20fb41a61ff0e4fa948bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -657,6 +657,9 @@ importers: '@t3tools/source-control-forgejo': specifier: workspace:* version: link:../../packages/source-control-forgejo + '@t3tools/source-control-gitlab': + specifier: workspace:* + version: link:../../packages/source-control-gitlab effect: specifier: 4.0.2 version: 4.0.2(patch_hash=ec61ee307eaec3e17f757e0e6a16296ea4b7a8c3188df0c6ec5e66301fd78688) @@ -700,6 +703,9 @@ importers: '@t3tools/shared': specifier: workspace:* version: link:../../packages/shared + '@t3tools/source-control-testing': + specifier: workspace:* + version: link:../../packages/source-control-testing '@t3tools/ssh': specifier: workspace:* version: link:../../packages/ssh @@ -1603,6 +1609,34 @@ importers: specifier: 1.0.0 version: 1.0.0(@types/node@24.12.4)(@vitest/ui@5.0.1(vitest@5.0.1))(bufferutil@4.1.0)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.1.0(@noble/hashes@1.8.0))(msw@2.12.11(@types/node@24.12.4)(typescript@7.0.2))(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0) + packages/source-control-gitlab: + dependencies: + '@t3tools/contracts': + specifier: workspace:* + version: link:../contracts + '@t3tools/shared': + specifier: workspace:* + version: link:../shared + '@t3tools/source-control-core': + specifier: workspace:* + version: link:../source-control-core + effect: + specifier: 4.0.2 + version: 4.0.2(patch_hash=ec61ee307eaec3e17f757e0e6a16296ea4b7a8c3188df0c6ec5e66301fd78688) + devDependencies: + '@effect/vitest': + specifier: 4.0.2 + version: 4.0.2(patch_hash=595b7d26fb635caba9c3d39fcb189bb78a000192f8d3b60ead7174b310d1ade9)(@types/node@24.12.4)(@vitest/ui@5.0.1)(bufferutil@4.1.0)(effect@4.0.2(patch_hash=ec61ee307eaec3e17f757e0e6a16296ea4b7a8c3188df0c6ec5e66301fd78688))(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.1.0(@noble/hashes@1.8.0))(msw@2.12.11(@types/node@24.12.4)(typescript@7.0.2))(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0) + '@t3tools/source-control-testing': + specifier: workspace:* + version: link:../source-control-testing + '@types/node': + specifier: 24.12.4 + version: 24.12.4 + vite-plus: + specifier: 1.0.0 + version: 1.0.0(@types/node@24.12.4)(@vitest/ui@5.0.1(vitest@5.0.1))(bufferutil@4.1.0)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.1.0(@noble/hashes@1.8.0))(msw@2.12.11(@types/node@24.12.4)(typescript@7.0.2))(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0) + packages/source-control-testing: dependencies: '@t3tools/contracts': diff --git a/scripts/release-smoke.ts b/scripts/release-smoke.ts index 7f29acf844a0dedb36c054e9e6c94ff80c91b3f1..c19a1ee9cac4b73fd498f50bd264a469425ecf86 100644 --- a/scripts/release-smoke.ts +++ b/scripts/release-smoke.ts @@ -40,6 +40,7 @@ const workspaceFiles = [ "packages/source-control-azure-devops/package.json", "packages/source-control-core/package.json", "packages/source-control-forgejo/package.json", + "packages/source-control-gitlab/package.json", "packages/source-control-testing/package.json", "packages/effect-acp/package.json", "packages/effect-codex-app-server/package.json", -- 2.54.0