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>
46 lines
2.1 KiB
TypeScript
46 lines
2.1 KiB
TypeScript
import type { ProjectSettings, Task, TaskStore } from "@fusion/core";
|
|
import { resolveGitLabTarget, safeLogGitLabEntry } from "./gitlab-lifecycle.js";
|
|
import { updateGitLabTargetState } from "./gitlab-tracking-state.js";
|
|
import { decideIssueAction } from "./github-tracking-state.js";
|
|
|
|
interface TaskMovedEvent { task: Task; from: string; to: string; }
|
|
|
|
export class GitLabSourceIssueCloseService {
|
|
private readonly defaultStore: TaskStore;
|
|
private readonly listeners = new Map<TaskStore, { onTaskMoved: (event: TaskMovedEvent) => void }>();
|
|
private started = false;
|
|
|
|
constructor(store: TaskStore) { this.defaultStore = store; }
|
|
|
|
start(): void { if (this.started) return; this.started = true; this.attach(this.defaultStore); }
|
|
stop(): void { if (!this.started) return; this.started = false; for (const store of this.listeners.keys()) this.detach(store); }
|
|
|
|
attach(store: TaskStore): void {
|
|
if (this.listeners.has(store)) return;
|
|
const onTaskMoved = (event: TaskMovedEvent): void => { void this.handleTaskMoved(store, event); };
|
|
this.listeners.set(store, { onTaskMoved });
|
|
if (this.started) store.on("task:moved", onTaskMoved);
|
|
}
|
|
|
|
detach(store: TaskStore): void {
|
|
const handlers = this.listeners.get(store);
|
|
if (!handlers) return;
|
|
store.off("task:moved", handlers.onTaskMoved);
|
|
this.listeners.delete(store);
|
|
}
|
|
|
|
private async handleTaskMoved(store: TaskStore, event: TaskMovedEvent): Promise<void> {
|
|
const settings = await store.getSettings() as Pick<ProjectSettings, "gitlabCloseSourceIssueOnDone">;
|
|
if (settings.gitlabCloseSourceIssueOnDone !== true) return;
|
|
if (event.task.sourceIssue?.provider !== "gitlab") return;
|
|
const decision = decideIssueAction(event.from, event.to);
|
|
if (!decision) return;
|
|
const target = resolveGitLabTarget(event.task);
|
|
if (!target) {
|
|
await safeLogGitLabEntry(store, event.task.id, "Skipped closing GitLab source issue", "Linked GitLab source metadata is incomplete");
|
|
return;
|
|
}
|
|
await updateGitLabTargetState(store, event.task.id, target, decision.action === "close" ? "closed" : "opened", "source");
|
|
}
|
|
}
|