fix(core): wire built-in GitLab integrations (#393)

* fix(core): register built-in GitLab plugins

* fix(core): infer missing GitLab project defaults
This commit is contained in:
Harsh Batheja 2026-03-10 12:57:35 +05:30 committed by deepak
parent f48c939d9b
commit 28b6d8ac5c
4 changed files with 95 additions and 5 deletions

View File

@ -418,4 +418,44 @@ describe("Config Defaults", () => {
const validated = validateConfig(config);
expect(validated.projects.proj1.tracker).toEqual({ plugin: "github" });
});
it("infers GitLab tracker default from scm plugin", () => {
const config = {
projects: {
proj1: {
path: "/repos/test",
repo: "org/test",
defaultBranch: "main",
scm: {
plugin: "gitlab",
host: "gitlab.company.com",
},
},
},
};
const validated = validateConfig(config);
expect(validated.projects.proj1.scm).toEqual({ plugin: "gitlab", host: "gitlab.company.com" });
expect(validated.projects.proj1.tracker).toEqual({ plugin: "gitlab" });
});
it("infers GitLab scm default from tracker plugin", () => {
const config = {
projects: {
proj1: {
path: "/repos/test",
repo: "org/test",
defaultBranch: "main",
tracker: {
plugin: "gitlab",
host: "gitlab.com",
},
},
},
};
const validated = validateConfig(config);
expect(validated.projects.proj1.tracker).toEqual({ plugin: "gitlab", host: "gitlab.com" });
expect(validated.projects.proj1.scm).toEqual({ plugin: "gitlab" });
});
});

View File

@ -165,6 +165,26 @@ describe("loadBuiltins", () => {
expect(registry.get("agent", "opencode")).not.toBeNull();
});
it("registers gitlab tracker and scm plugins from importFn", async () => {
const registry = createPluginRegistry();
const fakeTracker = makePlugin("tracker", "gitlab");
const fakeScm = makePlugin("scm", "gitlab");
await registry.loadBuiltins(undefined, async (pkg: string) => {
if (pkg === "@composio/ao-plugin-tracker-gitlab") return fakeTracker;
if (pkg === "@composio/ao-plugin-scm-gitlab") return fakeScm;
throw new Error(`Not found: ${pkg}`);
});
expect(registry.list("tracker")).toContainEqual(
expect.objectContaining({ name: "gitlab", slot: "tracker" }),
);
expect(registry.list("scm")).toContainEqual(
expect.objectContaining({ name: "gitlab", slot: "scm" }),
);
});
it("passes configured notifier plugin config to create()", async () => {
const registry = createPluginRegistry();
const fakeWebhookNotifier = makePlugin("notifier", "webhook");

View File

@ -18,6 +18,34 @@ import { z } from "zod";
import type { OrchestratorConfig } from "./types.js";
import { generateSessionPrefix } from "./paths.js";
function inferScmPlugin(project: {
repo: string;
scm?: Record<string, unknown>;
tracker?: Record<string, unknown>;
}): "github" | "gitlab" {
const scmPlugin = project.scm?.["plugin"];
if (scmPlugin === "gitlab") {
return "gitlab";
}
const scmHost = project.scm?.["host"];
if (typeof scmHost === "string" && scmHost.toLowerCase().includes("gitlab")) {
return "gitlab";
}
const trackerPlugin = project.tracker?.["plugin"];
if (trackerPlugin === "gitlab") {
return "gitlab";
}
const trackerHost = project.tracker?.["host"];
if (typeof trackerHost === "string" && trackerHost.toLowerCase().includes("gitlab")) {
return "gitlab";
}
return "github";
}
// =============================================================================
// ZOD SCHEMAS
// =============================================================================
@ -166,14 +194,16 @@ function applyProjectDefaults(config: OrchestratorConfig): OrchestratorConfig {
project.sessionPrefix = generateSessionPrefix(projectId);
}
const inferredPlugin = inferScmPlugin(project);
// Infer SCM from repo if not set
if (!project.scm && project.repo.includes("/")) {
project.scm = { plugin: "github" };
project.scm = { plugin: inferredPlugin };
}
// Infer tracker from repo if not set (default to github issues)
if (!project.tracker) {
project.tracker = { plugin: "github" };
project.tracker = { plugin: inferredPlugin };
}
}

View File

@ -38,8 +38,10 @@ const BUILTIN_PLUGINS: Array<{ slot: PluginSlot; name: string; pkg: string }> =
// Trackers
{ slot: "tracker", name: "github", pkg: "@composio/ao-plugin-tracker-github" },
{ slot: "tracker", name: "linear", pkg: "@composio/ao-plugin-tracker-linear" },
{ slot: "tracker", name: "gitlab", pkg: "@composio/ao-plugin-tracker-gitlab" },
// SCM
{ slot: "scm", name: "github", pkg: "@composio/ao-plugin-scm-github" },
{ slot: "scm", name: "gitlab", pkg: "@composio/ao-plugin-scm-gitlab" },
// Notifiers
{ slot: "notifier", name: "composio", pkg: "@composio/ao-plugin-notifier-composio" },
{ slot: "notifier", name: "desktop", pkg: "@composio/ao-plugin-notifier-desktop" },
@ -64,9 +66,7 @@ function extractPluginConfig(
if (!notifierConfig || typeof notifierConfig !== "object") continue;
const configuredPlugin = (notifierConfig as Record<string, unknown>)["plugin"];
const hasExplicitPlugin = typeof configuredPlugin === "string" && configuredPlugin.length > 0;
const matches = hasExplicitPlugin
? configuredPlugin === name
: notifierName === name;
const matches = hasExplicitPlugin ? configuredPlugin === name : notifierName === name;
if (matches) {
const { plugin: _plugin, ...rest } = notifierConfig as Record<string, unknown>;
return rest;