Files
fusion/packages/dashboard/src/__tests__/gitlab-issue-comment.test.ts
gsxdsm 34be333a2a FN-7426: add GitLab lifecycle automation
Add GitLab lifecycle automation for comments and source item state changes.

- Add GitLab REST helpers for posting notes and closing or reopening issues and merge requests.
- Register GitLab source-comment, tracking-comment, tracking-state, and source-close services with multi-project lifecycle wiring.
- Add project settings, documentation, tests, and a changeset for GitLab completion comments and auto-close behavior.

Files changed:
 .changeset/fn-7426-gitlab-lifecycle.md             |  7 ++
 docs/cli-reference.md                              |  2 +-
 docs/dashboard-guide.md                            |  3 +-
 docs/settings-reference.md                         |  5 +-
 packages/core/src/settings-schema.ts               |  3 +
 packages/core/src/types.ts                         | 10 +++
 .../src/__tests__/gitlab-issue-comment.test.ts     | 37 +++++++++
 .../__tests__/gitlab-source-issue-close.test.ts    | 29 +++++++
 .../src/__tests__/gitlab-tracking-comments.test.ts | 31 +++++++
 .../src/__tests__/gitlab-tracking-state.test.ts    | 42 ++++++++++
 packages/dashboard/src/__tests__/gitlab.test.ts    | 18 ++++
 .../register-git-github.gitlab-lifecycle.test.ts   | 54 ++++++++++++
 packages/dashboard/src/gitlab-issue-comment.ts     | 62 ++++++++++++++
 packages/dashboard/src/gitlab-lifecycle.ts         | 58 +++++++++++++
 .../dashboard/src/gitlab-source-issue-close.ts     | 45 ++++++++++
 packages/dashboard/src/gitlab-tracking-comments.ts | 77 +++++++++++++++++
 packages/dashboard/src/gitlab-tracking-state.ts    | 97 ++++++++++++++++++++++
 packages/dashboard/src/gitlab.ts                   | 30 +++++++
 .../dashboard/src/routes/register-git-github.ts    | 23 +++++
 19 files changed, 630 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7426

Fusion-Task-Lineage: a46bd11f-96ef-4291-ab41-829007fa057a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 11:38:34 -07:00

38 lines
2.5 KiB
TypeScript

import { EventEmitter } from "node:events";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { GitLabIssueCommentService } from "../gitlab-issue-comment.js";
function jsonResponse(body: unknown, status = 200) { return new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json" } }); }
function store(settings: any = {}) {
const emitter = new EventEmitter();
return Object.assign(emitter, {
getSettings: vi.fn().mockResolvedValue({ gitlabAuthToken: "token", gitlabInstanceUrl: "https://gitlab.example.com", gitlabCommentOnDone: true, ...settings }),
getGlobalSettingsStore: () => ({ getSettings: vi.fn().mockResolvedValue({}) }),
logEntry: vi.fn(),
});
}
const task: any = { id: "FN-1", title: "Fix", sourceIssue: { provider: "gitlab", repository: "g/p", issueNumber: 2, url: "https://gitlab.example.com/g/p/-/issues/2" }, gitlabTracking: { item: { kind: "project_issue", instanceUrl: "https://gitlab.example.com", host: "gitlab.example.com", url: "https://gitlab.example.com/g/p/-/issues/2", projectPath: "g/p", iid: 2, title: "Fix", state: "opened", linkedAt: "now" } } };
describe("GitLabIssueCommentService", () => {
beforeEach(() => vi.unstubAllGlobals());
it("posts source completion comments to GitLab project issues", async () => {
const fetchImpl = vi.fn().mockResolvedValue(jsonResponse({ id: 1 }));
vi.stubGlobal("fetch", fetchImpl);
const s = store();
new GitLabIssueCommentService(s as any).start();
s.emit("task:moved", { task, to: "done" });
await vi.waitFor(() => expect(fetchImpl).toHaveBeenCalled());
expect(fetchImpl.mock.calls[0][0]).toBe("https://gitlab.example.com/api/v4/projects/g%2Fp/issues/2/notes");
expect(s.logEntry).toHaveBeenCalledWith("FN-1", "Posted GitLab issue completion comment", "g/p#2");
});
it("skips non-GitLab and incomplete source metadata", async () => {
const fetchImpl = vi.fn(); vi.stubGlobal("fetch", fetchImpl);
const s = store(); new GitLabIssueCommentService(s as any).start();
s.emit("task:moved", { task: { ...task, sourceIssue: { provider: "github" } }, to: "done" });
s.emit("task:moved", { task: { id: "FN-2", sourceIssue: { provider: "gitlab" }, gitlabTracking: { item: { kind: "group_issue", iid: 3 } } }, to: "done" });
await new Promise((resolve) => setImmediate(resolve));
expect(fetchImpl).not.toHaveBeenCalled();
expect(s.logEntry).toHaveBeenCalledWith("FN-2", "Skipped GitLab source comment", "Linked GitLab source metadata is incomplete");
});
});