@mastra/factory 0.18.0-alpha.7 → 0.18.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boards/review.d.ts +2 -0
- package/dist/boards/review.d.ts.map +1 -1
- package/dist/boards/review.js +16 -6
- package/dist/boards/review.js.map +1 -1
- package/dist/boards/work-transition-policy.d.ts.map +1 -1
- package/dist/boards/work-transition-policy.js +10 -0
- package/dist/boards/work-transition-policy.js.map +1 -1
- package/dist/integrations/github/default-rules.d.ts +17 -1
- package/dist/integrations/github/default-rules.d.ts.map +1 -1
- package/dist/integrations/github/default-rules.js +28 -6
- package/dist/integrations/github/default-rules.js.map +1 -1
- package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +32 -5
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/gitlab/api.d.ts.map +1 -1
- package/dist/integrations/gitlab/api.js.map +1 -1
- package/dist/integrations/gitlab/default-rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/default-rules.js +1 -0
- package/dist/integrations/gitlab/default-rules.js.map +1 -1
- package/dist/integrations/gitlab/reconciler.d.ts.map +1 -1
- package/dist/integrations/gitlab/reconciler.js.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.d.ts.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
- package/dist/integrations/gitlab/rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/rules.js +66 -0
- package/dist/integrations/gitlab/rules.js.map +1 -1
- package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
- package/dist/integrations/gitlab/version-control.js.map +1 -1
- package/dist/integrations/incidentio/api.d.ts.map +1 -1
- package/dist/integrations/incidentio/api.js.map +1 -1
- package/dist/integrations/incidentio/intake.d.ts.map +1 -1
- package/dist/integrations/incidentio/intake.js.map +1 -1
- package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/issue-reconcile-worker.js.map +1 -1
- package/dist/integrations/platform/linear/event-worker.js.map +1 -1
- package/dist/integrations/slack/emoji-shortcodes.generated.js.map +1 -1
- package/dist/integrations/slack/feed-publisher.d.ts.map +1 -1
- package/dist/integrations/slack/feed-publisher.js.map +1 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +6 -0
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/tools.d.ts +1 -0
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +107 -32
- package/dist/rules/tools.js.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts.map +1 -1
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +5 -0
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/factory-skills/factory-gitlab-rereview/SKILL.md +3 -3
- package/factory-skills/factory-gitlab-review/SKILL.md +5 -5
- package/factory-skills/factory-rereview/SKILL.md +10 -12
- package/factory-skills/factory-review/SKILL.md +10 -12
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciler.js","names":[],"sources":["../../../src/integrations/gitlab/reconciler.ts"],"sourcesContent":["import type { IntegrationContext } from '../base.js';\nimport type { IssueReconciler, IssueReconcileSummary } from '../issue-reconciler.js';\nimport type { GitLabIntegrationBase } from './integration.js';\nimport { attachGitLabIssueReconciler } from './issue-reconciler.js';\nimport { attachGitLabMergeRequestReconciler } from './merge-request-reconciler.js';\n\nexport function attachGitLabReconciler(\n gitlab: GitLabIntegrationBase,\n context: IntegrationContext,\n): IssueReconciler | undefined {\n const issues = attachGitLabIssueReconciler(gitlab, context);\n const mergeRequests = attachGitLabMergeRequestReconciler(gitlab, context);\n if (!issues && !mergeRequests) return undefined;\n return async () => {\n const results = await Promise.all([issues?.(), mergeRequests?.()]);\n return results.filter((result): result is IssueReconcileSummary => result !== undefined).reduce(\n
|
|
1
|
+
{"version":3,"file":"reconciler.js","names":[],"sources":["../../../src/integrations/gitlab/reconciler.ts"],"sourcesContent":["import type { IntegrationContext } from '../base.js';\nimport type { IssueReconciler, IssueReconcileSummary } from '../issue-reconciler.js';\nimport type { GitLabIntegrationBase } from './integration.js';\nimport { attachGitLabIssueReconciler } from './issue-reconciler.js';\nimport { attachGitLabMergeRequestReconciler } from './merge-request-reconciler.js';\n\nexport function attachGitLabReconciler(\n gitlab: GitLabIntegrationBase,\n context: IntegrationContext,\n): IssueReconciler | undefined {\n const issues = attachGitLabIssueReconciler(gitlab, context);\n const mergeRequests = attachGitLabMergeRequestReconciler(gitlab, context);\n if (!issues && !mergeRequests) return undefined;\n return async () => {\n const results = await Promise.all([issues?.(), mergeRequests?.()]);\n return results\n .filter((result): result is IssueReconcileSummary => result !== undefined)\n .reduce(\n (summary, result) => ({\n projects: Math.max(summary.projects, result.projects),\n checked: summary.checked + result.checked,\n updated: summary.updated + result.updated,\n closed: summary.closed + result.closed,\n missing: summary.missing + result.missing,\n failed: summary.failed + result.failed,\n errors: [...summary.errors, ...result.errors],\n }),\n { projects: 0, checked: 0, updated: 0, closed: 0, missing: 0, failed: 0, errors: [] },\n );\n };\n}\n"],"mappings":";;;AAMA,SAAgB,uBACd,QACA,SAC6B;CAC7B,MAAM,SAAS,4BAA4B,QAAQ,OAAO;CAC1D,MAAM,gBAAgB,mCAAmC,QAAQ,OAAO;CACxE,IAAI,CAAC,UAAU,CAAC,eAAe,OAAO,KAAA;CACtC,OAAO,YAAY;EAEjB,QAAO,MADe,QAAQ,IAAI,CAAC,SAAS,GAAG,gBAAgB,CAAC,CAAC,EAAA,CAE9D,QAAQ,WAA4C,WAAW,KAAA,CAAS,CAAC,CACzE,QACE,SAAS,YAAY;GACpB,UAAU,KAAK,IAAI,QAAQ,UAAU,OAAO,QAAQ;GACpD,SAAS,QAAQ,UAAU,OAAO;GAClC,SAAS,QAAQ,UAAU,OAAO;GAClC,QAAQ,QAAQ,SAAS,OAAO;GAChC,SAAS,QAAQ,UAAU,OAAO;GAClC,QAAQ,QAAQ,SAAS,OAAO;GAChC,QAAQ,CAAC,GAAG,QAAQ,QAAQ,GAAG,OAAO,MAAM;EAC9C,IACA;GAAE,UAAU;GAAG,SAAS;GAAG,SAAS;GAAG,QAAQ;GAAG,SAAS;GAAG,QAAQ;GAAG,QAAQ,CAAC;EAAE,CACtF;CACJ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciliation-config.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/reconciliation-config.ts"],"names":[],"mappings":"AAMA,wBAAgB,2BAA2B,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"reconciliation-config.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/reconciliation-config.ts"],"names":[],"mappings":"AAMA,wBAAgB,2BAA2B,IAAI,OAAO,CAKrD;AAED,wBAAgB,4BAA4B,IAAI,MAAM,GAAG,SAAS,CAOjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciliation-config.js","names":[],"sources":["../../../src/integrations/gitlab/reconciliation-config.ts"],"sourcesContent":["import { optionalBoolean, optionalPositiveInteger } from '../reconciliation-config.js';\n\nfunction configuredValue(primary: string | undefined, legacy: string | undefined): string | undefined {\n return primary?.trim() ? primary : legacy;\n}\n\nexport function gitlabReconciliationEnabled(): boolean {\n const primary = process.env.MASTRACODE_GITLAB_RECONCILE_ENABLED;\n const value = configuredValue(primary, process.env.MASTRACODE_GITLAB_ISSUE_RECONCILE_ENABLED);\n const name = primary?.trim()
|
|
1
|
+
{"version":3,"file":"reconciliation-config.js","names":[],"sources":["../../../src/integrations/gitlab/reconciliation-config.ts"],"sourcesContent":["import { optionalBoolean, optionalPositiveInteger } from '../reconciliation-config.js';\n\nfunction configuredValue(primary: string | undefined, legacy: string | undefined): string | undefined {\n return primary?.trim() ? primary : legacy;\n}\n\nexport function gitlabReconciliationEnabled(): boolean {\n const primary = process.env.MASTRACODE_GITLAB_RECONCILE_ENABLED;\n const value = configuredValue(primary, process.env.MASTRACODE_GITLAB_ISSUE_RECONCILE_ENABLED);\n const name = primary?.trim() ? 'MASTRACODE_GITLAB_RECONCILE_ENABLED' : 'MASTRACODE_GITLAB_ISSUE_RECONCILE_ENABLED';\n return optionalBoolean(name, value, 'gitlab') ?? true;\n}\n\nexport function gitlabReconciliationInterval(): number | undefined {\n return optionalPositiveInteger(\n configuredValue(\n process.env.MASTRACODE_GITLAB_RECONCILE_INTERVAL_MS,\n process.env.MASTRACODE_GITLAB_ISSUE_RECONCILE_INTERVAL_MS,\n ),\n );\n}\n"],"mappings":";;AAEA,SAAS,gBAAgB,SAA6B,QAAgD;CACpG,OAAO,SAAS,KAAK,IAAI,UAAU;AACrC;AAEA,SAAgB,8BAAuC;CACrD,MAAM,UAAU,QAAQ,IAAI;CAC5B,MAAM,QAAQ,gBAAgB,SAAS,QAAQ,IAAI,yCAAyC;CAE5F,OAAO,gBADM,SAAS,KAAK,IAAI,wCAAwC,6CAC1C,OAAO,QAAQ,KAAK;AACnD;AAEA,SAAgB,+BAAmD;CACjE,OAAO,wBACL,gBACE,QAAQ,IAAI,yCACZ,QAAQ,IAAI,6CACd,CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/rules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAQ3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,8CAA8C,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/rules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAQ3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,8CAA8C,CAAC;AAEtD,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC9F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,KAAK,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AA+GtE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,8BAA8B,CAAC,CAAC,kBAAkB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3F,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACpH,yBAAyB,CACvB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,GAAG,eAAe,EAC/B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAChC;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,aAAa,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;CACvB;AAOD,qBAAa,WAAW;;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAElD,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,aAAa,CAAA;KAAE,CAAC;CAwd9E;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,CAAC,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAYhE"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assertFactoryDecisionTarget, validateFactoryRuleDecisions } from "../../rules/validation.js";
|
|
2
2
|
import { boardForWorkItem } from "../../boards/semantics.js";
|
|
3
3
|
import "../../boards/index.js";
|
|
4
|
+
import { WorkItemUpdateConflictError } from "../../storage/domains/work-items/base.js";
|
|
4
5
|
import { encodeIssueReference, encodeSourceId } from "./integration.js";
|
|
5
6
|
//#region src/integrations/gitlab/rules.ts
|
|
6
7
|
const RULE_TIMEOUT_MS = 5e3;
|
|
@@ -13,6 +14,13 @@ function string(value) {
|
|
|
13
14
|
function number(value) {
|
|
14
15
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
15
16
|
}
|
|
17
|
+
/** GitLab sends `2024-01-02T03:04:05Z` or `2024-01-02 03:04:05 UTC`. */
|
|
18
|
+
function timestamp(value) {
|
|
19
|
+
const text = string(value);
|
|
20
|
+
if (!text) return void 0;
|
|
21
|
+
const parsed = Date.parse(text.replace(" UTC", "Z").replace(" ", "T"));
|
|
22
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
23
|
+
}
|
|
16
24
|
function boolean(value) {
|
|
17
25
|
return typeof value === "boolean" ? value : void 0;
|
|
18
26
|
}
|
|
@@ -236,10 +244,68 @@ var GitLabRules = class {
|
|
|
236
244
|
item,
|
|
237
245
|
ingressIdentity: `gitlab:${projectId}:${parsed.deliveryId}${index ? `:${item?.id ?? index}` : ""}`
|
|
238
246
|
}));
|
|
247
|
+
const branchOwners = headBranch ? items.filter((item) => item.externalSource?.type !== "pull-request" && Object.values(item.sessions).some((session) => session.branch === headBranch)) : [];
|
|
248
|
+
if (authoringItem && mergeRequestIid && branchOwners.length === 1) await this.#trackOpenMergeRequest({
|
|
249
|
+
orgId: authoringItem.orgId,
|
|
250
|
+
id: authoringItem.id,
|
|
251
|
+
event,
|
|
252
|
+
mergeRequestIid,
|
|
253
|
+
eventAt: timestamp(mergeRequest?.updated_at),
|
|
254
|
+
opened: string(mergeRequest?.state) === "opened" && (actorTrusted || mergeRequestAuthorTrusted)
|
|
255
|
+
});
|
|
239
256
|
if (results.some((result) => result.status === "committed")) return { status: "committed" };
|
|
240
257
|
if (results.some((result) => result.status === "replayed")) return { status: "replayed" };
|
|
241
258
|
return results[0] ?? { status: "ignored" };
|
|
242
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* Records or clears the merge request a Work card has out. Each merge
|
|
262
|
+
* request's last applied event time is kept on the card, so an opening that
|
|
263
|
+
* is older than a close already applied (a replay, or a close delivered
|
|
264
|
+
* first) is ignored, while a genuine reopen is newer and records it again.
|
|
265
|
+
*/
|
|
266
|
+
async #trackOpenMergeRequest(input) {
|
|
267
|
+
const settling = input.event === "mergeRequestMerged" || input.event === "mergeRequestClosed";
|
|
268
|
+
if (input.event !== "mergeRequestOpened" && !settling) return;
|
|
269
|
+
const key = String(input.mergeRequestIid);
|
|
270
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
271
|
+
const item = await this.options.storage.get({
|
|
272
|
+
orgId: input.orgId,
|
|
273
|
+
id: input.id
|
|
274
|
+
});
|
|
275
|
+
if (!item) return;
|
|
276
|
+
const events = object(item.metadata?.mergeRequestEvents) ?? {};
|
|
277
|
+
const last = object(events[key]);
|
|
278
|
+
const lastAt = number(last?.at);
|
|
279
|
+
if (input.eventAt !== void 0 && lastAt !== void 0 && lastAt >= input.eventAt) return;
|
|
280
|
+
if (input.eventAt === void 0 && !settling && last?.open === false) return;
|
|
281
|
+
if (!settling && !input.opened) return;
|
|
282
|
+
const recorded = item.metadata?.openPullRequestNumber;
|
|
283
|
+
const patch = { mergeRequestEvents: {
|
|
284
|
+
...events,
|
|
285
|
+
[key]: {
|
|
286
|
+
at: input.eventAt ?? lastAt ?? null,
|
|
287
|
+
open: !settling
|
|
288
|
+
}
|
|
289
|
+
} };
|
|
290
|
+
if (!settling) patch.openPullRequestNumber = input.mergeRequestIid;
|
|
291
|
+
else if (recorded === input.mergeRequestIid) {
|
|
292
|
+
patch.openPullRequestNumber = null;
|
|
293
|
+
if (input.event === "mergeRequestMerged" && typeof item.metadata?.reviewVerdict === "string") patch.reviewVerdict = null;
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
await this.options.storage.update({
|
|
297
|
+
orgId: item.orgId,
|
|
298
|
+
id: item.id,
|
|
299
|
+
userId: "factory-rule-dispatcher",
|
|
300
|
+
expectedRevision: item.revision,
|
|
301
|
+
patch: { metadata: patch }
|
|
302
|
+
});
|
|
303
|
+
return;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
if (!(error instanceof WorkItemUpdateConflictError)) throw error;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
243
309
|
async #trusted(connectionIds, projectId, username) {
|
|
244
310
|
for (const connectionId of connectionIds) try {
|
|
245
311
|
const level = await this.options.gitlab.getProjectMemberAccessLevel(connectionId, projectId, username);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","names":["#targets","#ingestProject","#trusted","#evaluate"],"sources":["../../../src/integrations/gitlab/rules.ts"],"sourcesContent":["import { boardForWorkItem } from '../../boards/index.js';\nimport type { BoardRegistry } from '../../boards/index.js';\nimport type {\n FactoryGitLabEventName,\n FactoryGitLabRuleContext,\n FactoryRuleActor,\n FactoryRuleDecision,\n} from '../../rules/types.js';\nimport { assertFactoryDecisionTarget, validateFactoryRuleDecisions } from '../../rules/validation.js';\nimport type { IntakeStorage } from '../../storage/domains/intake/base.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type {\n ExternalRepositoryProjectTarget,\n SourceControlStorageHandle,\n} from '../../storage/domains/source-control/base.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../../storage/domains/work-items/base.js';\nimport type { IntegrationContext } from '../base.js';\nimport type { GitLabEventRules } from './default-rules.js';\nimport { encodeIssueReference, encodeSourceId, GITLAB_TRUSTED_ACCESS_LEVEL } from './integration.js';\nimport type { ParsedGitLabWebhook } from './webhook.js';\n\nconst RULE_TIMEOUT_MS = 5_000;\n\ntype IngressStatus = 'ignored' | 'committed' | 'replayed' | 'missing';\n\nfunction object(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction string(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction number(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction boolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction usernames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(entry => {\n const username = string(object(entry)?.username);\n return username ? [username] : [];\n });\n}\n\nfunction labelNames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(entry => {\n if (typeof entry === 'string') return entry ? [entry] : [];\n const title = string(object(entry)?.title) ?? string(object(entry)?.name);\n return title ? [title] : [];\n });\n}\n\nfunction labelColors(value: unknown): Record<string, string> {\n if (!Array.isArray(value)) return {};\n return Object.fromEntries(\n value.flatMap(entry => {\n const label = object(entry);\n const name = string(label?.title) ?? string(label?.name);\n const color = string(label?.color);\n return name && color ? [[name, color]] : [];\n }),\n );\n}\n\nfunction eventName(parsed: ParsedGitLabWebhook): FactoryGitLabEventName | undefined {\n const attributes = object(parsed.payload.object_attributes);\n const action = string(attributes?.action)?.toLowerCase();\n if (parsed.event === 'Issue Hook') {\n if (action === 'open' || action === 'reopen') return 'issueOpened';\n if (action === 'close') return 'issueClosed';\n return 'issueUpdated';\n }\n if (parsed.event === 'Note Hook') {\n const noteableType = string(attributes?.noteable_type);\n if (noteableType === 'Issue') return 'issueCommented';\n if (noteableType === 'MergeRequest') return 'mergeRequestCommented';\n return;\n }\n if (parsed.event !== 'Merge Request Hook') return;\n if (action === 'open' || action === 'reopen') return 'mergeRequestOpened';\n if (action === 'merge') return 'mergeRequestMerged';\n if (action === 'close') return 'mergeRequestClosed';\n return 'mergeRequestUpdated';\n}\n\nfunction normalizeHost(host: string): string {\n return host.trim().toLowerCase().replace(/\\.$/, '');\n}\n\nfunction hostFromPayload(parsed: ParsedGitLabWebhook): string | undefined {\n const declaredHost = parsed.instanceHost ? normalizeHost(parsed.instanceHost) : undefined;\n const projectUrl = string(object(parsed.payload.project)?.web_url);\n if (!projectUrl) return declaredHost;\n try {\n const payloadHost = normalizeHost(new URL(projectUrl).host);\n if (declaredHost && declaredHost !== payloadHost) return undefined;\n return payloadHost;\n } catch {\n return undefined;\n }\n}\n\nfunction mergeRequestSourceKey(host: string, projectId: number, mergeRequestIid: number): string {\n return `gitlab-pr:${Buffer.from(JSON.stringify({ version: 1, host, projectId, mergeRequestIid }), 'utf8').toString('base64url')}`;\n}\n\nasync function withRuleTimeout<T>(promise: Promise<T>): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('FACTORY_RULE_TIMEOUT')), RULE_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\nexport interface GitLabRulesIntegration {\n readonly rules: GitLabEventRules;\n resolveActiveConnectionForHost?(storedConnectionId: string, host: string): Promise<string>;\n getProjectMemberAccessLevel(connectionId: string, projectId: string, username: string): Promise<number | undefined>;\n getWorkItemAuthorUsername(\n connectionId: string,\n projectId: string,\n kind: 'issue' | 'merge_request',\n iid: number,\n ): Promise<string | undefined>;\n}\n\ninterface GitLabRulesOptions {\n gitlab: GitLabRulesIntegration;\n sourceControl: SourceControlStorageHandle;\n projects: FactoryProjectsStorage;\n storage: WorkItemsStorage;\n intake: IntakeStorage;\n configVersion: string;\n boards: BoardRegistry;\n}\n\ninterface ProjectTarget {\n target: ExternalRepositoryProjectTarget;\n connectionIds: string[];\n}\n\nexport class GitLabRules {\n constructor(private readonly options: GitLabRulesOptions) {}\n\n async ingest(parsed: ParsedGitLabWebhook): Promise<{ status: IngressStatus }> {\n const event = eventName(parsed);\n const project = object(parsed.payload.project);\n const projectId = number(project?.id);\n const projectPath = string(project?.path_with_namespace);\n const host = hostFromPayload(parsed);\n const username = string(parsed.payload.user_username) ?? string(object(parsed.payload.user)?.username);\n if (!event || !projectId || !projectPath || !host || !username) return { status: 'ignored' };\n\n const targets = await this.#targets(String(projectId), host);\n if (targets.length === 0) return { status: 'ignored' };\n const results: Array<{ status: IngressStatus }> = [];\n for (const target of targets) {\n results.push(await this.#ingestProject(parsed, event, projectId, projectPath, host, username, target));\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n async #targets(repositoryExternalId: string, host: string): Promise<ProjectTarget[]> {\n const grouped = new Map<string, ProjectTarget>();\n const keys = (await this.options.sourceControl.projectRepositories.listConfiguredExternalKeys()).filter(\n key => key.repositoryExternalId === repositoryExternalId,\n );\n for (const key of keys) {\n const targets = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: key.installationExternalId,\n repositoryExternalId,\n });\n for (const target of targets) {\n const installation = await this.options.sourceControl.installations.findByExternalId({\n orgId: target.orgId,\n externalId: key.installationExternalId,\n });\n const installationHost = string(installation?.providerMetadata.host);\n if (!installationHost || normalizeHost(installationHost) !== normalizeHost(host)) continue;\n const id = `${target.orgId}:${target.factoryProjectId}`;\n const current = grouped.get(id);\n if (current) {\n if (!current.connectionIds.includes(key.installationExternalId)) {\n current.connectionIds.push(key.installationExternalId);\n }\n } else {\n grouped.set(id, { target, connectionIds: [key.installationExternalId] });\n }\n }\n }\n return [...grouped.values()];\n }\n\n async #ingestProject(\n parsed: ParsedGitLabWebhook,\n event: FactoryGitLabEventName,\n projectId: number,\n projectPath: string,\n host: string,\n username: string,\n target: ProjectTarget,\n ): Promise<{ status: IngressStatus }> {\n const factoryProject = await this.options.projects.get({\n orgId: target.target.orgId,\n id: target.target.factoryProjectId,\n });\n if (!factoryProject) return { status: 'missing' };\n\n const sourceId = encodeSourceId({ host, projectId: String(projectId) });\n const config = await this.options.intake.getConfig({\n orgId: target.target.orgId,\n integrationIds: ['gitlab'],\n });\n if (!config.gitlab?.enabled || !config.gitlab.sourceIds?.includes(sourceId)) return { status: 'ignored' };\n const binding = (await this.options.intake.listBindings({ orgId: target.target.orgId, integrationId: 'gitlab' })).find(\n candidate => candidate.sourceId === sourceId && candidate.factoryProjectId === target.target.factoryProjectId,\n );\n if (!binding) return { status: 'ignored' };\n const board = this.options.boards.get(binding.board ?? 'work');\n if (!board) return { status: 'ignored' };\n\n const connectionIds = [\n ...new Set(\n await Promise.all(\n target.connectionIds.map(connectionId =>\n this.options.gitlab.resolveActiveConnectionForHost?.(connectionId, host) ?? connectionId,\n ),\n ),\n ),\n ];\n\n const attributes = object(parsed.payload.object_attributes);\n const issue = parsed.event === 'Note Hook' ? object(parsed.payload.issue) : attributes;\n const mergeRequest = parsed.event === 'Note Hook' ? object(parsed.payload.merge_request) : attributes;\n const issueIid = number(issue?.iid);\n const mergeRequestIid = number(mergeRequest?.iid);\n const issueSourceKey = issueIid\n ? encodeIssueReference({ host, projectId: String(projectId), issueIid })\n : undefined;\n const mergeRequestKey = mergeRequestIid ? mergeRequestSourceKey(host, projectId, mergeRequestIid) : undefined;\n const items = await this.options.storage.list({\n orgId: target.target.orgId,\n factoryProjectId: target.target.factoryProjectId,\n });\n const issueItem = issueSourceKey\n ? items.find(item => item.externalSource?.integrationId === 'gitlab' && item.externalSource.externalId === issueSourceKey)\n : undefined;\n const reviewItem = mergeRequestKey\n ? items.find(item => item.externalSource?.integrationId === 'gitlab' && item.externalSource.externalId === mergeRequestKey)\n : undefined;\n const headBranch = string(mergeRequest?.source_branch) ?? '';\n const authoringItem = headBranch\n ? items.find(\n item =>\n item.externalSource?.type !== 'pull-request' &&\n Object.values(item.sessions).some(session => session.branch === headBranch),\n )\n : undefined;\n const actorTrusted = await this.#trusted(connectionIds, String(projectId), username);\n const eventUserId = number(object(parsed.payload.user)?.id) ?? number(parsed.payload.user_id);\n const resolveAuthor = async (\n item: Record<string, unknown> | undefined,\n kind: 'issue' | 'merge_request',\n iid: number | undefined,\n ): Promise<string | undefined> => {\n if (!item || !iid) return undefined;\n const embedded = string(object(item.author)?.username);\n if (embedded) return embedded;\n if (eventUserId && eventUserId === number(item.author_id)) return username;\n for (const connectionId of connectionIds) {\n try {\n const resolved = await this.options.gitlab.getWorkItemAuthorUsername(\n connectionId,\n String(projectId),\n kind,\n iid,\n );\n if (resolved) return resolved;\n } catch {\n // Another active credential may cover this project; otherwise leave author trust unset.\n }\n }\n return undefined;\n };\n const [issueAuthor, mergeRequestAuthor] = await Promise.all([\n resolveAuthor(issue, 'issue', issueIid),\n resolveAuthor(mergeRequest, 'merge_request', mergeRequestIid),\n ]);\n const authorTrusted = async (author: string | undefined): Promise<boolean> => {\n if (!author) return false;\n return author === username\n ? actorTrusted\n : this.#trusted(connectionIds, String(projectId), author);\n };\n const [issueAuthorTrusted, mergeRequestAuthorTrusted] = await Promise.all([\n authorTrusted(issueAuthor),\n authorTrusted(mergeRequestAuthor),\n ]);\n const actor: FactoryRuleActor = {\n type: 'gitlab',\n username,\n trusted: actorTrusted,\n factoryAuthored: false,\n };\n\n const candidates: Array<WorkItemRow | undefined> =\n event === 'mergeRequestMerged'\n ? [...new Map([reviewItem, authoringItem].filter(Boolean).map(item => [item!.id, item!])).values()]\n : event === 'mergeRequestCommented'\n ? [authoringItem ?? reviewItem]\n : event === 'mergeRequestOpened'\n ? [authoringItem]\n : event.startsWith('mergeRequest')\n ? [reviewItem ?? authoringItem]\n : [issueItem];\n const results = [];\n for (const [index, item] of candidates.entries()) {\n results.push(\n await this.#evaluate({\n parsed,\n event,\n projectId,\n projectPath,\n host,\n actor,\n orgId: target.target.orgId,\n factoryProjectId: target.target.factoryProjectId,\n factoryProject,\n board: { board: board.id, initialPhase: board.initialPhase },\n issue,\n issueAuthor,\n issueAuthorTrusted,\n issueIid,\n issueSourceKey,\n mergeRequest,\n mergeRequestAuthor,\n mergeRequestAuthorTrusted,\n mergeRequestIid,\n mergeRequestKey,\n factoryAuthored: Boolean(authoringItem),\n item,\n ingressIdentity: `gitlab:${projectId}:${parsed.deliveryId}${index ? `:${item?.id ?? index}` : ''}`,\n }),\n );\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n async #trusted(connectionIds: string[], projectId: string, username: string): Promise<boolean> {\n for (const connectionId of connectionIds) {\n try {\n const level = await this.options.gitlab.getProjectMemberAccessLevel(connectionId, projectId, username);\n if (level !== undefined) return level >= GITLAB_TRUSTED_ACCESS_LEVEL;\n } catch {\n // Try another active credential covering the same canonical project; otherwise fail closed.\n }\n }\n return false;\n }\n\n async #evaluate(input: {\n parsed: ParsedGitLabWebhook;\n event: FactoryGitLabEventName;\n projectId: number;\n projectPath: string;\n host: string;\n actor: FactoryRuleActor;\n orgId: string;\n factoryProjectId: string;\n factoryProject: { createdAt: Date };\n board: { board: string; initialPhase: string };\n issue: Record<string, unknown> | undefined;\n issueAuthor: string | undefined;\n issueAuthorTrusted: boolean;\n issueIid: number | undefined;\n issueSourceKey: string | undefined;\n mergeRequest: Record<string, unknown> | undefined;\n mergeRequestAuthor: string | undefined;\n mergeRequestAuthorTrusted: boolean;\n mergeRequestIid: number | undefined;\n mergeRequestKey: string | undefined;\n factoryAuthored: boolean;\n item: WorkItemRow | undefined;\n ingressIdentity: string;\n }): Promise<{ status: IngressStatus }> {\n const note = object(input.parsed.payload.object_attributes);\n const issueAuthor = input.issueAuthor;\n const mergeRequestAuthor = input.mergeRequestAuthor;\n const mergeRequestState = string(input.mergeRequest?.state);\n const context: FactoryGitLabRuleContext = {\n tenant: { orgId: input.orgId, projectId: input.factoryProjectId },\n actor: input.actor,\n ingress: { type: 'gitlab', id: input.ingressIdentity },\n cause: `gitlab.${input.event}`,\n causalChain: [],\n configVersion: this.options.configVersion,\n ...(input.item\n ? {\n item: {\n id: input.item.id,\n source:\n input.item.externalSource?.type === 'pull-request'\n ? ('gitlab-pr' as const)\n : input.item.externalSource?.integrationId === 'gitlab'\n ? ('gitlab-issue' as const)\n : ('manual' as const),\n sourceKey: input.item.externalSource?.externalId ?? null,\n parentWorkItemId: input.item.parentWorkItemId,\n title: input.item.title,\n url: input.item.externalSource?.url ?? null,\n stages: input.item.stages,\n acceptedAt: input.item.acceptedAt,\n metadata: input.item.metadata,\n },\n board: boardForWorkItem(input.item),\n itemRevision: input.item.revision,\n }\n : {}),\n intake: input.board,\n event: input.event,\n deliveryId: input.parsed.deliveryId,\n factory: { createdAt: input.factoryProject.createdAt.toISOString() },\n repository: { id: input.projectId, fullName: input.projectPath, host: input.host },\n ...(input.issueIid && input.issueSourceKey && string(input.issue?.title)\n ? {\n issue: {\n number: input.issueIid,\n sourceKey: input.issueSourceKey,\n title: string(input.issue?.title)!,\n url:\n string(input.issue?.url) ??\n string(input.issue?.web_url) ??\n `https://${input.host}/${input.projectPath}/-/issues/${input.issueIid}`,\n ...(string(input.issue?.created_at) ? { createdAt: string(input.issue?.created_at) } : {}),\n ...(string(input.issue?.updated_at) ? { updatedAt: string(input.issue?.updated_at) } : {}),\n assignees: usernames(input.parsed.payload.assignees ?? input.issue?.assignees),\n labels: labelNames(input.issue?.labels ?? input.parsed.payload.labels),\n labelColors: labelColors(input.issue?.labels ?? input.parsed.payload.labels),\n state: string(input.issue?.state) === 'closed' ? ('closed' as const) : ('open' as const),\n ...(issueAuthor ? { author: issueAuthor } : {}),\n authorTrusted: input.issueAuthorTrusted,\n },\n }\n : {}),\n ...(input.parsed.event === 'Note Hook' && number(note?.id)\n ? {\n note: {\n id: number(note?.id)!,\n ...(string(note?.note) ? { body: string(note?.note) } : {}),\n ...(string(note?.url) ? { url: string(note?.url) } : {}),\n ...(string(object(input.parsed.payload.user)?.username)\n ? { author: string(object(input.parsed.payload.user)?.username) }\n : {}),\n ...(string(note?.created_at) ? { createdAt: string(note?.created_at) } : {}),\n ...(string(note?.updated_at) ? { updatedAt: string(note?.updated_at) } : {}),\n },\n }\n : {}),\n ...(input.mergeRequestIid && input.mergeRequestKey && string(input.mergeRequest?.title)\n ? {\n mergeRequest: {\n number: input.mergeRequestIid,\n sourceKey: input.mergeRequestKey,\n title: string(input.mergeRequest?.title)!,\n url:\n string(input.mergeRequest?.url) ??\n string(input.mergeRequest?.web_url) ??\n `https://${input.host}/${input.projectPath}/-/merge_requests/${input.mergeRequestIid}`,\n ...(string(input.mergeRequest?.created_at)\n ? { createdAt: string(input.mergeRequest?.created_at) }\n : {}),\n state: mergeRequestState === 'closed' || mergeRequestState === 'merged' ? ('closed' as const) : ('open' as const),\n draft: boolean(input.mergeRequest?.draft) ?? boolean(input.mergeRequest?.work_in_progress) ?? false,\n merged: input.event === 'mergeRequestMerged' || mergeRequestState === 'merged',\n assignees: usernames(input.parsed.payload.assignees ?? input.mergeRequest?.assignees),\n reviewers: usernames(input.parsed.payload.reviewers ?? input.mergeRequest?.reviewers),\n labels: labelNames(input.mergeRequest?.labels ?? input.parsed.payload.labels),\n labelColors: labelColors(input.mergeRequest?.labels ?? input.parsed.payload.labels),\n ...(mergeRequestAuthor ? { author: mergeRequestAuthor } : {}),\n authorTrusted: input.mergeRequestAuthorTrusted,\n factoryAuthored: input.factoryAuthored,\n headBranch: string(input.mergeRequest?.source_branch) ?? '',\n baseBranch: string(input.mergeRequest?.target_branch) ?? '',\n },\n }\n : {}),\n };\n const rule = this.options.gitlab.rules[input.event];\n let decision: FactoryRuleDecision | void;\n let decisions: Record<string, unknown>[] = [];\n let outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string } = { status: 'accepted' };\n try {\n decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : undefined;\n if (decision?.type === 'reject') {\n outcome = { status: 'rejected', code: decision.code, reason: decision.reason };\n } else if (decision) {\n decisions = validateFactoryRuleDecisions([decision]).map(entry => {\n assertFactoryDecisionTarget(entry, this.options.boards, input.item ? boardForWorkItem(input.item) : undefined);\n return { ...entry };\n });\n }\n } catch (error) {\n const timedOut = error instanceof Error && error.message === 'FACTORY_RULE_TIMEOUT';\n outcome = {\n status: 'rejected',\n code: timedOut ? 'timeout' : 'rule_error',\n reason: timedOut\n ? 'Factory rule evaluation timed out.'\n : error instanceof Error\n ? error.message.slice(0, 2_000)\n : 'Factory GitLab rule failed.',\n };\n }\n\n const committed = await this.options.storage.commitRuleEvaluation({\n orgId: input.orgId,\n factoryProjectId: input.factoryProjectId,\n workItemId: input.item?.id ?? null,\n ingress: { identity: input.ingressIdentity, triggerType: `gitlab.${input.event}` },\n configVersion: this.options.configVersion,\n expectedRevision: input.item?.revision ?? null,\n actor: { ...input.actor },\n outcome,\n decisions,\n causalChain: [],\n now: new Date(),\n });\n return { status: committed.status };\n }\n}\n\nexport function attachGitLabRules(\n gitlab: GitLabRulesIntegration,\n context: IntegrationContext,\n): ((event: ParsedGitLabWebhook) => Promise<unknown>) | undefined {\n if (!context.runtime) return undefined;\n const rules = new GitLabRules({\n gitlab,\n sourceControl: context.storage.sourceControl,\n projects: context.storage.projects,\n storage: context.runtime.workItems,\n intake: context.storage.intake,\n configVersion: context.runtime.configVersion,\n boards: context.runtime.boards,\n });\n return event => rules.ingest(event);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rules.js","names":["#targets","#ingestProject","#trusted","#evaluate","#trackOpenMergeRequest"],"sources":["../../../src/integrations/gitlab/rules.ts"],"sourcesContent":["import { boardForWorkItem } from '../../boards/index.js';\nimport type { BoardRegistry } from '../../boards/index.js';\nimport type {\n FactoryGitLabEventName,\n FactoryGitLabRuleContext,\n FactoryRuleActor,\n FactoryRuleDecision,\n} from '../../rules/types.js';\nimport { assertFactoryDecisionTarget, validateFactoryRuleDecisions } from '../../rules/validation.js';\nimport type { IntakeStorage } from '../../storage/domains/intake/base.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type {\n ExternalRepositoryProjectTarget,\n SourceControlStorageHandle,\n} from '../../storage/domains/source-control/base.js';\nimport { WorkItemUpdateConflictError } from '../../storage/domains/work-items/base.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../../storage/domains/work-items/base.js';\nimport type { IntegrationContext } from '../base.js';\nimport type { GitLabEventRules } from './default-rules.js';\nimport { encodeIssueReference, encodeSourceId, GITLAB_TRUSTED_ACCESS_LEVEL } from './integration.js';\nimport type { ParsedGitLabWebhook } from './webhook.js';\n\nconst RULE_TIMEOUT_MS = 5_000;\n\ntype IngressStatus = 'ignored' | 'committed' | 'replayed' | 'missing';\n\nfunction object(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction string(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction number(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\n/** GitLab sends `2024-01-02T03:04:05Z` or `2024-01-02 03:04:05 UTC`. */\nfunction timestamp(value: unknown): number | undefined {\n const text = string(value);\n if (!text) return undefined;\n const parsed = Date.parse(text.replace(' UTC', 'Z').replace(' ', 'T'));\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction boolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction usernames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(entry => {\n const username = string(object(entry)?.username);\n return username ? [username] : [];\n });\n}\n\nfunction labelNames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(entry => {\n if (typeof entry === 'string') return entry ? [entry] : [];\n const title = string(object(entry)?.title) ?? string(object(entry)?.name);\n return title ? [title] : [];\n });\n}\n\nfunction labelColors(value: unknown): Record<string, string> {\n if (!Array.isArray(value)) return {};\n return Object.fromEntries(\n value.flatMap(entry => {\n const label = object(entry);\n const name = string(label?.title) ?? string(label?.name);\n const color = string(label?.color);\n return name && color ? [[name, color]] : [];\n }),\n );\n}\n\nfunction eventName(parsed: ParsedGitLabWebhook): FactoryGitLabEventName | undefined {\n const attributes = object(parsed.payload.object_attributes);\n const action = string(attributes?.action)?.toLowerCase();\n if (parsed.event === 'Issue Hook') {\n if (action === 'open' || action === 'reopen') return 'issueOpened';\n if (action === 'close') return 'issueClosed';\n return 'issueUpdated';\n }\n if (parsed.event === 'Note Hook') {\n const noteableType = string(attributes?.noteable_type);\n if (noteableType === 'Issue') return 'issueCommented';\n if (noteableType === 'MergeRequest') return 'mergeRequestCommented';\n return;\n }\n if (parsed.event !== 'Merge Request Hook') return;\n if (action === 'open' || action === 'reopen') return 'mergeRequestOpened';\n if (action === 'merge') return 'mergeRequestMerged';\n if (action === 'close') return 'mergeRequestClosed';\n return 'mergeRequestUpdated';\n}\n\nfunction normalizeHost(host: string): string {\n return host.trim().toLowerCase().replace(/\\.$/, '');\n}\n\nfunction hostFromPayload(parsed: ParsedGitLabWebhook): string | undefined {\n const declaredHost = parsed.instanceHost ? normalizeHost(parsed.instanceHost) : undefined;\n const projectUrl = string(object(parsed.payload.project)?.web_url);\n if (!projectUrl) return declaredHost;\n try {\n const payloadHost = normalizeHost(new URL(projectUrl).host);\n if (declaredHost && declaredHost !== payloadHost) return undefined;\n return payloadHost;\n } catch {\n return undefined;\n }\n}\n\nfunction mergeRequestSourceKey(host: string, projectId: number, mergeRequestIid: number): string {\n return `gitlab-pr:${Buffer.from(JSON.stringify({ version: 1, host, projectId, mergeRequestIid }), 'utf8').toString('base64url')}`;\n}\n\nasync function withRuleTimeout<T>(promise: Promise<T>): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('FACTORY_RULE_TIMEOUT')), RULE_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\nexport interface GitLabRulesIntegration {\n readonly rules: GitLabEventRules;\n resolveActiveConnectionForHost?(storedConnectionId: string, host: string): Promise<string>;\n getProjectMemberAccessLevel(connectionId: string, projectId: string, username: string): Promise<number | undefined>;\n getWorkItemAuthorUsername(\n connectionId: string,\n projectId: string,\n kind: 'issue' | 'merge_request',\n iid: number,\n ): Promise<string | undefined>;\n}\n\ninterface GitLabRulesOptions {\n gitlab: GitLabRulesIntegration;\n sourceControl: SourceControlStorageHandle;\n projects: FactoryProjectsStorage;\n storage: WorkItemsStorage;\n intake: IntakeStorage;\n configVersion: string;\n boards: BoardRegistry;\n}\n\ninterface ProjectTarget {\n target: ExternalRepositoryProjectTarget;\n connectionIds: string[];\n}\n\nexport class GitLabRules {\n constructor(private readonly options: GitLabRulesOptions) {}\n\n async ingest(parsed: ParsedGitLabWebhook): Promise<{ status: IngressStatus }> {\n const event = eventName(parsed);\n const project = object(parsed.payload.project);\n const projectId = number(project?.id);\n const projectPath = string(project?.path_with_namespace);\n const host = hostFromPayload(parsed);\n const username = string(parsed.payload.user_username) ?? string(object(parsed.payload.user)?.username);\n if (!event || !projectId || !projectPath || !host || !username) return { status: 'ignored' };\n\n const targets = await this.#targets(String(projectId), host);\n if (targets.length === 0) return { status: 'ignored' };\n const results: Array<{ status: IngressStatus }> = [];\n for (const target of targets) {\n results.push(await this.#ingestProject(parsed, event, projectId, projectPath, host, username, target));\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n async #targets(repositoryExternalId: string, host: string): Promise<ProjectTarget[]> {\n const grouped = new Map<string, ProjectTarget>();\n const keys = (await this.options.sourceControl.projectRepositories.listConfiguredExternalKeys()).filter(\n key => key.repositoryExternalId === repositoryExternalId,\n );\n for (const key of keys) {\n const targets = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: key.installationExternalId,\n repositoryExternalId,\n });\n for (const target of targets) {\n const installation = await this.options.sourceControl.installations.findByExternalId({\n orgId: target.orgId,\n externalId: key.installationExternalId,\n });\n const installationHost = string(installation?.providerMetadata.host);\n if (!installationHost || normalizeHost(installationHost) !== normalizeHost(host)) continue;\n const id = `${target.orgId}:${target.factoryProjectId}`;\n const current = grouped.get(id);\n if (current) {\n if (!current.connectionIds.includes(key.installationExternalId)) {\n current.connectionIds.push(key.installationExternalId);\n }\n } else {\n grouped.set(id, { target, connectionIds: [key.installationExternalId] });\n }\n }\n }\n return [...grouped.values()];\n }\n\n async #ingestProject(\n parsed: ParsedGitLabWebhook,\n event: FactoryGitLabEventName,\n projectId: number,\n projectPath: string,\n host: string,\n username: string,\n target: ProjectTarget,\n ): Promise<{ status: IngressStatus }> {\n const factoryProject = await this.options.projects.get({\n orgId: target.target.orgId,\n id: target.target.factoryProjectId,\n });\n if (!factoryProject) return { status: 'missing' };\n\n const sourceId = encodeSourceId({ host, projectId: String(projectId) });\n const config = await this.options.intake.getConfig({\n orgId: target.target.orgId,\n integrationIds: ['gitlab'],\n });\n if (!config.gitlab?.enabled || !config.gitlab.sourceIds?.includes(sourceId)) return { status: 'ignored' };\n const binding = (\n await this.options.intake.listBindings({ orgId: target.target.orgId, integrationId: 'gitlab' })\n ).find(\n candidate => candidate.sourceId === sourceId && candidate.factoryProjectId === target.target.factoryProjectId,\n );\n if (!binding) return { status: 'ignored' };\n const board = this.options.boards.get(binding.board ?? 'work');\n if (!board) return { status: 'ignored' };\n\n const connectionIds = [\n ...new Set(\n await Promise.all(\n target.connectionIds.map(\n connectionId => this.options.gitlab.resolveActiveConnectionForHost?.(connectionId, host) ?? connectionId,\n ),\n ),\n ),\n ];\n\n const attributes = object(parsed.payload.object_attributes);\n const issue = parsed.event === 'Note Hook' ? object(parsed.payload.issue) : attributes;\n const mergeRequest = parsed.event === 'Note Hook' ? object(parsed.payload.merge_request) : attributes;\n const issueIid = number(issue?.iid);\n const mergeRequestIid = number(mergeRequest?.iid);\n const issueSourceKey = issueIid\n ? encodeIssueReference({ host, projectId: String(projectId), issueIid })\n : undefined;\n const mergeRequestKey = mergeRequestIid ? mergeRequestSourceKey(host, projectId, mergeRequestIid) : undefined;\n const items = await this.options.storage.list({\n orgId: target.target.orgId,\n factoryProjectId: target.target.factoryProjectId,\n });\n const issueItem = issueSourceKey\n ? items.find(\n item => item.externalSource?.integrationId === 'gitlab' && item.externalSource.externalId === issueSourceKey,\n )\n : undefined;\n const reviewItem = mergeRequestKey\n ? items.find(\n item => item.externalSource?.integrationId === 'gitlab' && item.externalSource.externalId === mergeRequestKey,\n )\n : undefined;\n const headBranch = string(mergeRequest?.source_branch) ?? '';\n const authoringItem = headBranch\n ? items.find(\n item =>\n item.externalSource?.type !== 'pull-request' &&\n Object.values(item.sessions).some(session => session.branch === headBranch),\n )\n : undefined;\n const actorTrusted = await this.#trusted(connectionIds, String(projectId), username);\n const eventUserId = number(object(parsed.payload.user)?.id) ?? number(parsed.payload.user_id);\n const resolveAuthor = async (\n item: Record<string, unknown> | undefined,\n kind: 'issue' | 'merge_request',\n iid: number | undefined,\n ): Promise<string | undefined> => {\n if (!item || !iid) return undefined;\n const embedded = string(object(item.author)?.username);\n if (embedded) return embedded;\n if (eventUserId && eventUserId === number(item.author_id)) return username;\n for (const connectionId of connectionIds) {\n try {\n const resolved = await this.options.gitlab.getWorkItemAuthorUsername(\n connectionId,\n String(projectId),\n kind,\n iid,\n );\n if (resolved) return resolved;\n } catch {\n // Another active credential may cover this project; otherwise leave author trust unset.\n }\n }\n return undefined;\n };\n const [issueAuthor, mergeRequestAuthor] = await Promise.all([\n resolveAuthor(issue, 'issue', issueIid),\n resolveAuthor(mergeRequest, 'merge_request', mergeRequestIid),\n ]);\n const authorTrusted = async (author: string | undefined): Promise<boolean> => {\n if (!author) return false;\n return author === username ? actorTrusted : this.#trusted(connectionIds, String(projectId), author);\n };\n const [issueAuthorTrusted, mergeRequestAuthorTrusted] = await Promise.all([\n authorTrusted(issueAuthor),\n authorTrusted(mergeRequestAuthor),\n ]);\n const actor: FactoryRuleActor = {\n type: 'gitlab',\n username,\n trusted: actorTrusted,\n factoryAuthored: false,\n };\n\n const candidates: Array<WorkItemRow | undefined> =\n event === 'mergeRequestMerged'\n ? [...new Map([reviewItem, authoringItem].filter(Boolean).map(item => [item!.id, item!])).values()]\n : event === 'mergeRequestCommented'\n ? [authoringItem ?? reviewItem]\n : event === 'mergeRequestOpened'\n ? [authoringItem]\n : event.startsWith('mergeRequest')\n ? [reviewItem ?? authoringItem]\n : [issueItem];\n const results = [];\n for (const [index, item] of candidates.entries()) {\n results.push(\n await this.#evaluate({\n parsed,\n event,\n projectId,\n projectPath,\n host,\n actor,\n orgId: target.target.orgId,\n factoryProjectId: target.target.factoryProjectId,\n factoryProject,\n board: { board: board.id, initialPhase: board.initialPhase },\n issue,\n issueAuthor,\n issueAuthorTrusted,\n issueIid,\n issueSourceKey,\n mergeRequest,\n mergeRequestAuthor,\n mergeRequestAuthorTrusted,\n mergeRequestIid,\n mergeRequestKey,\n factoryAuthored: Boolean(authoringItem),\n item,\n ingressIdentity: `gitlab:${projectId}:${parsed.deliveryId}${index ? `:${item?.id ?? index}` : ''}`,\n }),\n );\n }\n // The authoring Work item records which merge request it has out, so the\n // Work transition policy keeps an agent from closing the work while it is\n // open. Sessions carry no repository, so a branch shared by two Work cards\n // is ambiguous and records nothing.\n const branchOwners = headBranch\n ? items.filter(\n item =>\n item.externalSource?.type !== 'pull-request' &&\n Object.values(item.sessions).some(session => session.branch === headBranch),\n )\n : [];\n if (authoringItem && mergeRequestIid && branchOwners.length === 1) {\n await this.#trackOpenMergeRequest({\n orgId: authoringItem.orgId,\n id: authoringItem.id,\n event,\n mergeRequestIid,\n eventAt: timestamp(mergeRequest?.updated_at),\n opened: string(mergeRequest?.state) === 'opened' && (actorTrusted || mergeRequestAuthorTrusted),\n });\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n /**\n * Records or clears the merge request a Work card has out. Each merge\n * request's last applied event time is kept on the card, so an opening that\n * is older than a close already applied (a replay, or a close delivered\n * first) is ignored, while a genuine reopen is newer and records it again.\n */\n async #trackOpenMergeRequest(input: {\n orgId: string;\n id: string;\n event: string;\n mergeRequestIid: number;\n eventAt: number | undefined;\n opened: boolean;\n }): Promise<void> {\n const settling = input.event === 'mergeRequestMerged' || input.event === 'mergeRequestClosed';\n if (input.event !== 'mergeRequestOpened' && !settling) return;\n const key = String(input.mergeRequestIid);\n for (let attempt = 0; attempt < 3; attempt++) {\n const item = await this.options.storage.get({ orgId: input.orgId, id: input.id });\n if (!item) return;\n const events = object(item.metadata?.mergeRequestEvents) ?? {};\n const last = object(events[key]);\n const lastAt = number(last?.at);\n if (input.eventAt !== undefined && lastAt !== undefined && lastAt >= input.eventAt) return;\n // Without a timestamp, only an opening that no close has settled is trusted.\n if (input.eventAt === undefined && !settling && last?.open === false) return;\n if (!settling && !input.opened) return;\n const recorded = item.metadata?.openPullRequestNumber;\n const patch: Record<string, unknown> = {\n mergeRequestEvents: { ...events, [key]: { at: input.eventAt ?? lastAt ?? null, open: !settling } },\n };\n if (!settling) patch.openPullRequestNumber = input.mergeRequestIid;\n else if (recorded === input.mergeRequestIid) {\n patch.openPullRequestNumber = null;\n if (input.event === 'mergeRequestMerged' && typeof item.metadata?.reviewVerdict === 'string') {\n patch.reviewVerdict = null;\n }\n }\n try {\n await this.options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: 'factory-rule-dispatcher',\n expectedRevision: item.revision,\n patch: { metadata: patch },\n });\n return;\n } catch (error) {\n if (!(error instanceof WorkItemUpdateConflictError)) throw error;\n }\n }\n }\n\n async #trusted(connectionIds: string[], projectId: string, username: string): Promise<boolean> {\n for (const connectionId of connectionIds) {\n try {\n const level = await this.options.gitlab.getProjectMemberAccessLevel(connectionId, projectId, username);\n if (level !== undefined) return level >= GITLAB_TRUSTED_ACCESS_LEVEL;\n } catch {\n // Try another active credential covering the same canonical project; otherwise fail closed.\n }\n }\n return false;\n }\n\n async #evaluate(input: {\n parsed: ParsedGitLabWebhook;\n event: FactoryGitLabEventName;\n projectId: number;\n projectPath: string;\n host: string;\n actor: FactoryRuleActor;\n orgId: string;\n factoryProjectId: string;\n factoryProject: { createdAt: Date };\n board: { board: string; initialPhase: string };\n issue: Record<string, unknown> | undefined;\n issueAuthor: string | undefined;\n issueAuthorTrusted: boolean;\n issueIid: number | undefined;\n issueSourceKey: string | undefined;\n mergeRequest: Record<string, unknown> | undefined;\n mergeRequestAuthor: string | undefined;\n mergeRequestAuthorTrusted: boolean;\n mergeRequestIid: number | undefined;\n mergeRequestKey: string | undefined;\n factoryAuthored: boolean;\n item: WorkItemRow | undefined;\n ingressIdentity: string;\n }): Promise<{ status: IngressStatus }> {\n const note = object(input.parsed.payload.object_attributes);\n const issueAuthor = input.issueAuthor;\n const mergeRequestAuthor = input.mergeRequestAuthor;\n const mergeRequestState = string(input.mergeRequest?.state);\n const context: FactoryGitLabRuleContext = {\n tenant: { orgId: input.orgId, projectId: input.factoryProjectId },\n actor: input.actor,\n ingress: { type: 'gitlab', id: input.ingressIdentity },\n cause: `gitlab.${input.event}`,\n causalChain: [],\n configVersion: this.options.configVersion,\n ...(input.item\n ? {\n item: {\n id: input.item.id,\n source:\n input.item.externalSource?.type === 'pull-request'\n ? ('gitlab-pr' as const)\n : input.item.externalSource?.integrationId === 'gitlab'\n ? ('gitlab-issue' as const)\n : ('manual' as const),\n sourceKey: input.item.externalSource?.externalId ?? null,\n parentWorkItemId: input.item.parentWorkItemId,\n title: input.item.title,\n url: input.item.externalSource?.url ?? null,\n stages: input.item.stages,\n acceptedAt: input.item.acceptedAt,\n metadata: input.item.metadata,\n },\n board: boardForWorkItem(input.item),\n itemRevision: input.item.revision,\n }\n : {}),\n intake: input.board,\n event: input.event,\n deliveryId: input.parsed.deliveryId,\n factory: { createdAt: input.factoryProject.createdAt.toISOString() },\n repository: { id: input.projectId, fullName: input.projectPath, host: input.host },\n ...(input.issueIid && input.issueSourceKey && string(input.issue?.title)\n ? {\n issue: {\n number: input.issueIid,\n sourceKey: input.issueSourceKey,\n title: string(input.issue?.title)!,\n url:\n string(input.issue?.url) ??\n string(input.issue?.web_url) ??\n `https://${input.host}/${input.projectPath}/-/issues/${input.issueIid}`,\n ...(string(input.issue?.created_at) ? { createdAt: string(input.issue?.created_at) } : {}),\n ...(string(input.issue?.updated_at) ? { updatedAt: string(input.issue?.updated_at) } : {}),\n assignees: usernames(input.parsed.payload.assignees ?? input.issue?.assignees),\n labels: labelNames(input.issue?.labels ?? input.parsed.payload.labels),\n labelColors: labelColors(input.issue?.labels ?? input.parsed.payload.labels),\n state: string(input.issue?.state) === 'closed' ? ('closed' as const) : ('open' as const),\n ...(issueAuthor ? { author: issueAuthor } : {}),\n authorTrusted: input.issueAuthorTrusted,\n },\n }\n : {}),\n ...(input.parsed.event === 'Note Hook' && number(note?.id)\n ? {\n note: {\n id: number(note?.id)!,\n ...(string(note?.note) ? { body: string(note?.note) } : {}),\n ...(string(note?.url) ? { url: string(note?.url) } : {}),\n ...(string(object(input.parsed.payload.user)?.username)\n ? { author: string(object(input.parsed.payload.user)?.username) }\n : {}),\n ...(string(note?.created_at) ? { createdAt: string(note?.created_at) } : {}),\n ...(string(note?.updated_at) ? { updatedAt: string(note?.updated_at) } : {}),\n },\n }\n : {}),\n ...(input.mergeRequestIid && input.mergeRequestKey && string(input.mergeRequest?.title)\n ? {\n mergeRequest: {\n number: input.mergeRequestIid,\n sourceKey: input.mergeRequestKey,\n title: string(input.mergeRequest?.title)!,\n url:\n string(input.mergeRequest?.url) ??\n string(input.mergeRequest?.web_url) ??\n `https://${input.host}/${input.projectPath}/-/merge_requests/${input.mergeRequestIid}`,\n ...(string(input.mergeRequest?.created_at) ? { createdAt: string(input.mergeRequest?.created_at) } : {}),\n state:\n mergeRequestState === 'closed' || mergeRequestState === 'merged'\n ? ('closed' as const)\n : ('open' as const),\n draft: boolean(input.mergeRequest?.draft) ?? boolean(input.mergeRequest?.work_in_progress) ?? false,\n merged: input.event === 'mergeRequestMerged' || mergeRequestState === 'merged',\n assignees: usernames(input.parsed.payload.assignees ?? input.mergeRequest?.assignees),\n reviewers: usernames(input.parsed.payload.reviewers ?? input.mergeRequest?.reviewers),\n labels: labelNames(input.mergeRequest?.labels ?? input.parsed.payload.labels),\n labelColors: labelColors(input.mergeRequest?.labels ?? input.parsed.payload.labels),\n ...(mergeRequestAuthor ? { author: mergeRequestAuthor } : {}),\n authorTrusted: input.mergeRequestAuthorTrusted,\n factoryAuthored: input.factoryAuthored,\n headBranch: string(input.mergeRequest?.source_branch) ?? '',\n baseBranch: string(input.mergeRequest?.target_branch) ?? '',\n },\n }\n : {}),\n };\n const rule = this.options.gitlab.rules[input.event];\n let decision: FactoryRuleDecision | void;\n let decisions: Record<string, unknown>[] = [];\n let outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string } = { status: 'accepted' };\n try {\n decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : undefined;\n if (decision?.type === 'reject') {\n outcome = { status: 'rejected', code: decision.code, reason: decision.reason };\n } else if (decision) {\n decisions = validateFactoryRuleDecisions([decision]).map(entry => {\n assertFactoryDecisionTarget(\n entry,\n this.options.boards,\n input.item ? boardForWorkItem(input.item) : undefined,\n );\n return { ...entry };\n });\n }\n } catch (error) {\n const timedOut = error instanceof Error && error.message === 'FACTORY_RULE_TIMEOUT';\n outcome = {\n status: 'rejected',\n code: timedOut ? 'timeout' : 'rule_error',\n reason: timedOut\n ? 'Factory rule evaluation timed out.'\n : error instanceof Error\n ? error.message.slice(0, 2_000)\n : 'Factory GitLab rule failed.',\n };\n }\n\n const committed = await this.options.storage.commitRuleEvaluation({\n orgId: input.orgId,\n factoryProjectId: input.factoryProjectId,\n workItemId: input.item?.id ?? null,\n ingress: { identity: input.ingressIdentity, triggerType: `gitlab.${input.event}` },\n configVersion: this.options.configVersion,\n expectedRevision: input.item?.revision ?? null,\n actor: { ...input.actor },\n outcome,\n decisions,\n causalChain: [],\n now: new Date(),\n });\n return { status: committed.status };\n }\n}\n\nexport function attachGitLabRules(\n gitlab: GitLabRulesIntegration,\n context: IntegrationContext,\n): ((event: ParsedGitLabWebhook) => Promise<unknown>) | undefined {\n if (!context.runtime) return undefined;\n const rules = new GitLabRules({\n gitlab,\n sourceControl: context.storage.sourceControl,\n projects: context.storage.projects,\n storage: context.runtime.workItems,\n intake: context.storage.intake,\n configVersion: context.runtime.configVersion,\n boards: context.runtime.boards,\n });\n return event => rules.ingest(event);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-control.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/version-control.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAMV,cAAc,EACf,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,KAAK,EACV,eAAe,EAOhB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,eAAe,CAAC;IACrB,UAAU,EAAE,qBAAqB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,gCAAgC;IAC/C,oBAAoB,CAAC,UAAU,EAAE,qBAAqB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC9F,4BAA4B,CAAC,
|
|
1
|
+
{"version":3,"file":"version-control.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/version-control.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAMV,cAAc,EACf,MAAM,uCAAuC,CAAC;AAQ/C,OAAO,KAAK,EACV,eAAe,EAOhB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,eAAe,CAAC;IACrB,UAAU,EAAE,qBAAqB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,gCAAgC;IAC/C,oBAAoB,CAAC,UAAU,EAAE,qBAAqB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC9F,4BAA4B,CAAC,CAC3B,UAAU,EAAE,qBAAqB,EACjC,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,OAAO,CAAC,2BAA2B,CAAC,CAAC;CACzC;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,gCAAgC,GAAG,cAAc,CA4fhG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-control.js","names":[],"sources":["../../../src/integrations/gitlab/version-control.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nimport type { IntegrationConnection } from '../../capabilities/connection.js';\nimport type {\n PullRequest,\n PullRequestComment,\n RequestedReviewers,\n Review,\n ReviewComment,\n VersionControl,\n} from '../../capabilities/version-control.js';\nimport type { SourceControlStorageHandle } from '../../storage/domains/source-control/base.js';\nimport {\n GITLAB_DISCUSSIONS_PAGE_SIZE,\n GITLAB_MERGE_REQUESTS_PAGE_SIZE,\n GITLAB_NOTES_PAGE_SIZE,\n GitLabApiError,\n} from './api.js';\nimport type {\n GitLabApiClient,\n GitLabDiscussionNote,\n GitLabDiscussionPosition,\n GitLabMember,\n GitLabMergeRequest,\n GitLabNote,\n GitLabUser,\n} from './api.js';\n\nexport interface GitLabVersionControlContext {\n api: GitLabApiClient;\n connection: IntegrationConnection;\n host: string;\n webBaseUrl?: string;\n repositoryAccessToken?: () => Promise<string>;\n}\n\nexport interface GitLabVersionControlDependencies {\n contextForConnection(connection: IntegrationConnection): Promise<GitLabVersionControlContext>;\n contextForStoredInstallation?(connection: IntegrationConnection, host: string | undefined): Promise<GitLabVersionControlContext>;\n}\n\nexport function buildGitLabVersionControl(deps: GitLabVersionControlDependencies): VersionControl {\n let storage: SourceControlStorageHandle | undefined;\n\n const sourceControlStorage = (): SourceControlStorageHandle => {\n if (!storage) throw new Error('GitLab VersionControl is not initialized.');\n return storage;\n };\n\n const listPullRequests: VersionControl['listPullRequests'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const page = parsePositiveCursor(input.cursor);\n const state = input.state === 'open' ? 'opened' : input.state === 'closed' ? 'all' : (input.state ?? 'opened');\n const mergeRequests = await context.api.listMergeRequests(input.sourceId, { page, state });\n return {\n pullRequests: mergeRequests\n .filter(mergeRequest => input.state !== 'closed' || mergeRequest.state === 'closed' || mergeRequest.state === 'merged')\n .filter(mergeRequest => input.includeDrafts !== false || !isDraft(mergeRequest))\n .map(toPullRequest),\n nextCursor: mergeRequests.length === GITLAB_MERGE_REQUESTS_PAGE_SIZE ? String(page + 1) : null,\n };\n };\n\n const getPullRequest: VersionControl['getPullRequest'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n try {\n return toPullRequest(\n await context.api.getMergeRequest(input.sourceId, requirePositiveId(input.pullRequestId, 'merge request')),\n );\n } catch (error) {\n if (error instanceof GitLabApiError && error.status === 404) return null;\n throw error;\n }\n };\n\n const createPullRequest: VersionControl['createPullRequest'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const title = input.draft && !/^(?:draft:|\\[draft\\])/i.test(input.title) ? `Draft: ${input.title}` : input.title;\n return toPullRequest(\n await context.api.createMergeRequest(input.sourceId, {\n sourceBranch: input.headBranch,\n targetBranch: input.baseBranch,\n title,\n description: input.body,\n }),\n );\n };\n\n const updatePullRequest: VersionControl['updatePullRequest'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n return toPullRequest(\n await context.api.updateMergeRequest(input.sourceId, requirePositiveId(input.pullRequestId, 'merge request'), {\n title: input.title,\n description: input.body === null ? '' : input.body,\n targetBranch: input.baseBranch,\n stateEvent: input.state === 'closed' ? 'close' : input.state === 'open' ? 'reopen' : undefined,\n }),\n );\n };\n\n const closePullRequest: VersionControl['closePullRequest'] = input =>\n updatePullRequest({ ...input, state: 'closed' });\n\n const mergePullRequest: VersionControl['mergePullRequest'] = async input => {\n if (input.method === 'rebase') {\n throw notSupported('GitLab rebases merge requests asynchronously; rebase-and-merge is not supported.');\n }\n const context = await deps.contextForConnection(input.connection);\n const commitMessage = combinedCommitMessage(input.commitTitle, input.commitMessage);\n const result = await context.api.mergeMergeRequest(\n input.sourceId,\n requirePositiveId(input.pullRequestId, 'merge request'),\n {\n squash: input.method === 'squash',\n mergeCommitMessage: input.method === 'squash' ? undefined : commitMessage,\n squashCommitMessage: input.method === 'squash' ? commitMessage : undefined,\n },\n );\n const merged = result.state === 'merged' || Boolean(result.merged_at);\n return {\n merged,\n message: result.message ?? (merged ? 'Merge request merged.' : 'Merge request was not merged.'),\n sha: result.squash_commit_sha ?? result.merge_commit_sha ?? result.sha ?? null,\n };\n };\n\n const listComments: VersionControl['listComments'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const page = parsePositiveCursor(input.cursor);\n const notes = await context.api.listMergeRequestNotes(input.sourceId, mergeRequestIid, { page });\n return {\n comments: notes\n .filter(note => !note.system && note.type !== 'DiffNote')\n .map(note => toPullRequestComment(webBaseUrl(context), input.sourceId, mergeRequestIid, note)),\n nextCursor: notes.length === GITLAB_NOTES_PAGE_SIZE ? String(page + 1) : null,\n };\n };\n\n const createComment: VersionControl['createComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const note = await context.api.createMergeRequestNote(input.sourceId, mergeRequestIid, input.body);\n return toPullRequestComment(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n };\n\n const updateComment: VersionControl['updateComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const { mergeRequestIid, noteId } = parseNoteId(input.commentId);\n const note = await context.api.updateMergeRequestNote(input.sourceId, mergeRequestIid, noteId, input.body);\n return toPullRequestComment(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n };\n\n const deleteComment: VersionControl['deleteComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const { mergeRequestIid, noteId } = parseNoteId(input.commentId);\n await context.api.deleteMergeRequestNote(input.sourceId, mergeRequestIid, noteId);\n };\n\n const listReviews: VersionControl['listReviews'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const approvals = await context.api.getMergeRequestApprovals(input.sourceId, mergeRequestIid);\n return {\n reviews: (approvals.approved_by ?? []).map(({ user }) =>\n toApprovalReview(webBaseUrl(context), input.sourceId, mergeRequestIid, user),\n ),\n nextCursor: null,\n };\n };\n\n const getReview: VersionControl['getReview'] = async input => {\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const approvalPrefix = `${mergeRequestIid}:approval`;\n const commentPrefix = `${mergeRequestIid}:comment:`;\n if (input.reviewId !== approvalPrefix && !input.reviewId.startsWith(`${approvalPrefix}:`) && !input.reviewId.startsWith(commentPrefix)) {\n return null;\n }\n const context = await deps.contextForConnection(input.connection);\n if (input.reviewId === approvalPrefix || input.reviewId.startsWith(`${approvalPrefix}:`)) {\n const reviewerKey = input.reviewId === approvalPrefix ? null : input.reviewId.slice(approvalPrefix.length + 1);\n if (reviewerKey === '') return null;\n const currentUser = reviewerKey === null ? await context.api.getCurrentUser() : null;\n const approvals = await context.api.getMergeRequestApprovals(input.sourceId, mergeRequestIid);\n const user = (approvals.approved_by ?? []).map(entry => entry.user).find(candidate =>\n reviewerKey === null\n ? (currentUser?.id !== undefined && candidate.id === currentUser.id) ||\n candidate.username === currentUser?.username\n : String(candidate.id ?? candidate.username) === reviewerKey,\n );\n return user ? toApprovalReview(webBaseUrl(context), input.sourceId, mergeRequestIid, user) : null;\n }\n const noteId = parsePositiveInteger(input.reviewId.slice(commentPrefix.length));\n if (noteId === null) return null;\n try {\n const note = await context.api.getMergeRequestNote(input.sourceId, mergeRequestIid, noteId);\n if (note.system || note.type === 'DiffNote') return null;\n return toCommentReview(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n } catch (error) {\n if (error instanceof GitLabApiError && error.status === 404) return null;\n throw error;\n }\n };\n\n const createReview: VersionControl['createReview'] = async input =>\n submitReviewAction(deps, {\n connection: input.connection,\n sourceId: input.sourceId,\n pullRequestId: input.pullRequestId,\n event: input.event,\n body: input.body,\n commitId: input.commitId,\n });\n\n const updateReview: VersionControl['updateReview'] = async () => {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab does not expose mutable pending review objects.');\n };\n\n const submitReview: VersionControl['submitReview'] = async input =>\n submitReviewAction(deps, {\n connection: input.connection,\n sourceId: input.sourceId,\n pullRequestId: input.pullRequestId,\n event: input.event,\n body: input.body,\n });\n\n const dismissReview: VersionControl['dismissReview'] = async () => {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab approval dismissal has no GitHub review equivalent.');\n };\n\n const deletePendingReview: VersionControl['deletePendingReview'] = async () => {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab does not expose pending review objects.');\n };\n\n const listReviewComments: VersionControl['listReviewComments'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const page = parsePositiveCursor(input.cursor);\n const discussions = await context.api.listMergeRequestDiscussions(input.sourceId, mergeRequestIid, { page });\n return {\n comments: discussions.flatMap(discussion => {\n const position = discussionPosition(discussion.notes);\n if (!position) return [];\n const root = discussion.notes.find(note => note.position) ?? discussion.notes[0];\n const replyToId = root ? packDiscussionNoteId(mergeRequestIid, discussion.id, root.id) : null;\n return discussion.notes\n .filter(note => !note.system)\n .map(note =>\n toReviewComment(\n webBaseUrl(context),\n input.sourceId,\n mergeRequestIid,\n discussion.id,\n note,\n note === root ? null : replyToId,\n position,\n ),\n );\n }),\n nextCursor: discussions.length === GITLAB_DISCUSSIONS_PAGE_SIZE ? String(page + 1) : null,\n };\n };\n\n const createReviewComment: VersionControl['createReviewComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n if (input.replyToId) {\n const thread = parseReviewReplyId(input.replyToId);\n if (thread.mergeRequestIid !== mergeRequestIid) {\n throw new GitLabApiError('GitLab discussion does not belong to the requested merge request.', 400);\n }\n const discussion = await context.api.getMergeRequestDiscussion(\n input.sourceId,\n mergeRequestIid,\n thread.discussionId,\n );\n const position = discussionPosition(discussion.notes);\n if (!position) throw new GitLabApiError('GitLab discussion is not anchored to a diff.', 400);\n const root = discussion.notes.find(note => note.position) ?? discussion.notes[0];\n if (!root) throw new GitLabApiError('GitLab discussion response did not include a note.', 502);\n const note = await context.api.addMergeRequestDiscussionNote(\n input.sourceId,\n mergeRequestIid,\n thread.discussionId,\n input.body,\n );\n return toReviewComment(\n webBaseUrl(context),\n input.sourceId,\n mergeRequestIid,\n thread.discussionId,\n note,\n packDiscussionNoteId(mergeRequestIid, thread.discussionId, root.id),\n position,\n );\n }\n\n const mergeRequest = await context.api.getMergeRequest(input.sourceId, mergeRequestIid);\n if (!mergeRequest.diff_refs) {\n throw new GitLabApiError('GitLab merge request diff refs are not ready.', 409);\n }\n if (mergeRequest.diff_refs.head_sha !== input.commitId) {\n throw new GitLabApiError('GitLab merge request changed since this review comment was prepared.', 409);\n }\n const { path, line, side } = input;\n if (typeof path !== 'string' || typeof line !== 'number' || (side !== 'left' && side !== 'right')) {\n throw new GitLabApiError('GitLab diff review comment position is invalid.', 400);\n }\n if ((input.startLine === undefined) !== (input.startSide === undefined)) {\n throw new GitLabApiError('A multi-line GitLab review comment requires both startLine and startSide.', 400);\n }\n const position: GitLabDiscussionPosition = {\n position_type: 'text',\n ...mergeRequest.diff_refs,\n old_path: path,\n new_path: path,\n old_line: side === 'left' ? line : undefined,\n new_line: side === 'right' ? line : undefined,\n ...(input.startLine !== undefined && input.startSide\n ? {\n line_range: {\n start: discussionLine(path, input.startLine, input.startSide),\n end: discussionLine(path, line, side),\n },\n }\n : {}),\n };\n const discussion = await context.api.createMergeRequestDiscussion(input.sourceId, mergeRequestIid, {\n body: input.body,\n commitId: input.commitId,\n position,\n });\n const note = discussion.notes.find(candidate => candidate.position) ?? discussion.notes[0];\n if (!note) throw new GitLabApiError('GitLab discussion response did not include a note.', 502);\n return toReviewComment(webBaseUrl(context), input.sourceId, mergeRequestIid, discussion.id, note, null, position);\n };\n\n const updateReviewComment: VersionControl['updateReviewComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const reference = parseDiscussionNoteId(input.commentId);\n const discussion = await context.api.getMergeRequestDiscussion(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n );\n const position = discussionPosition(discussion.notes);\n if (!position) throw new GitLabApiError('GitLab discussion is not anchored to a diff.', 400);\n const root = discussion.notes.find(candidate => candidate.position) ?? discussion.notes[0];\n if (!root) throw new GitLabApiError('GitLab discussion response did not include a note.', 502);\n const note = await context.api.updateMergeRequestDiscussionNote(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n reference.noteId,\n input.body,\n );\n return toReviewComment(\n webBaseUrl(context),\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n note,\n note.id === root.id ? null : packDiscussionNoteId(reference.mergeRequestIid, reference.discussionId, root.id),\n position,\n );\n };\n\n const deleteReviewComment: VersionControl['deleteReviewComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const reference = parseDiscussionNoteId(input.commentId);\n await context.api.deleteMergeRequestDiscussionNote(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n reference.noteId,\n );\n };\n\n const resolveReviewThread: NonNullable<VersionControl['resolveReviewThread']> = async input => {\n const context = await deps.contextForConnection(input.connection);\n const reference = parseDiscussionNoteId(input.commentId);\n await context.api.resolveMergeRequestDiscussion(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n input.resolved,\n );\n };\n\n const listRequestedReviewers: VersionControl['listRequestedReviewers'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequest = await context.api.getMergeRequest(\n input.sourceId,\n requirePositiveId(input.pullRequestId, 'merge request'),\n );\n return toRequestedReviewers(mergeRequest);\n };\n\n const requestReviewers: VersionControl['requestReviewers'] = async input => {\n rejectTeamReviewers(input.teams);\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const mergeRequest = await context.api.getMergeRequest(input.sourceId, mergeRequestIid);\n const requestedMembers = await resolveMembers(context.api, input.sourceId, input.users ?? []);\n const currentIds = await reviewerIds(context.api, input.sourceId, mergeRequest.reviewers ?? []);\n const reviewerIdsToSet = [...new Set([...currentIds, ...requestedMembers.map(member => member.id)])];\n return toRequestedReviewers(\n await context.api.setMergeRequestReviewers(input.sourceId, mergeRequestIid, reviewerIdsToSet),\n );\n };\n\n const removeRequestedReviewers: VersionControl['removeRequestedReviewers'] = async input => {\n rejectTeamReviewers(input.teams);\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const mergeRequest = await context.api.getMergeRequest(input.sourceId, mergeRequestIid);\n const removals = new Set((input.users ?? []).map(username => username.toLowerCase()));\n const retained = (mergeRequest.reviewers ?? []).filter(user => !removals.has(user.username.toLowerCase()));\n const retainedIds = await reviewerIds(context.api, input.sourceId, retained);\n return toRequestedReviewers(\n await context.api.setMergeRequestReviewers(input.sourceId, mergeRequestIid, retainedIds),\n );\n };\n\n return {\n initialize: input => {\n storage = input.storage;\n },\n registerInstallation: async ({ orgId, userId, installation }) => {\n const requestedConnection = parseConnection(installation.metadata?.connection);\n if (!requestedConnection) {\n throw new GitLabApiError('GitLab installation metadata must include a valid connection.', 400);\n }\n const context = await deps.contextForConnection(requestedConnection);\n return sourceControlStorage().installations.upsert({\n orgId,\n connectedByUserId: userId,\n externalId: installation.externalId,\n accountName: installation.accountName,\n accountType: installation.accountType,\n providerMetadata: {\n ...installation.metadata,\n connection: context.connection,\n host: normalizeHost(context.host),\n },\n });\n },\n registerRepositories: async ({ orgId, installationId, repositories }) => {\n const normalizedRepositories = repositories.map(repository => ({\n ...repository,\n slug: normalizeSlug(repository.slug),\n }));\n return await Promise.all(\n normalizedRepositories.map(repository =>\n sourceControlStorage().repositories.upsert({\n orgId,\n input: {\n installationId,\n externalId: repository.externalId,\n slug: repository.slug,\n defaultBranch: repository.defaultBranch,\n providerMetadata: repository.metadata,\n },\n }),\n ),\n );\n },\n getRepositoryTarget: async ({ orgId, repositoryId }) => {\n const repository = await sourceControlStorage().repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const installation = await sourceControlStorage().installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) throw new Error('Version-control installation not found.');\n const connection = parseConnection(installation.providerMetadata.connection);\n if (!connection) throw new GitLabApiError('GitLab installation connection metadata is invalid.', 500);\n const context = await (deps.contextForStoredInstallation ?? deps.contextForConnection)(\n connection,\n typeof installation.providerMetadata.host === 'string' ? installation.providerMetadata.host : undefined,\n );\n // The API uses GitLab's immutable numeric project ID because Platform's\n // proxy normalizes encoded path slashes; retain the slug for browser URLs.\n return { connection: context.connection, sourceId: `${repository.externalId}:${repository.slug}` };\n },\n getRepositoryAccess: async ({ orgId, repositoryId }) => {\n const repository = await sourceControlStorage().repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const installation = await sourceControlStorage().installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) throw new Error('Version-control installation not found.');\n const connection = parseConnection(installation.providerMetadata.connection);\n if (!connection) throw new GitLabApiError('GitLab installation connection metadata is invalid.', 500);\n const context = await (deps.contextForStoredInstallation ?? deps.contextForConnection)(\n connection,\n typeof installation.providerMetadata.host === 'string' ? installation.providerMetadata.host : undefined,\n );\n if (!context.repositoryAccessToken) {\n throw notSupported('This GitLab connection does not expose credentials for repository cloning.');\n }\n const token = await context.repositoryAccessToken();\n const baseUrl = webBaseUrl(context);\n const slug = normalizeSlug(repository.slug);\n return {\n cloneUrl: `${baseUrl}/${slug}.git`,\n authorization: { scheme: 'bearer', token, username: 'oauth2' },\n };\n },\n listPullRequests,\n getPullRequest,\n createPullRequest,\n updatePullRequest,\n closePullRequest,\n mergePullRequest,\n listComments,\n resolveReviewThread,\n createComment,\n updateComment,\n deleteComment,\n listReviews,\n getReview,\n createReview,\n updateReview,\n submitReview,\n dismissReview,\n deletePendingReview,\n listReviewComments,\n createReviewComment,\n updateReviewComment,\n deleteReviewComment,\n listRequestedReviewers,\n requestReviewers,\n removeRequestedReviewers,\n };\n}\n\nasync function submitReviewAction(\n deps: GitLabVersionControlDependencies,\n input: {\n connection: IntegrationConnection;\n sourceId: string;\n pullRequestId: string;\n event: 'approve' | 'request-changes' | 'comment' | undefined;\n body?: string;\n commitId?: string;\n },\n): Promise<Review> {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n if (input.event === 'request-changes') {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab has no first-class request-changes review event.');\n }\n if (input.event === undefined) {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab has no first-class pending review object.');\n }\n if (input.event === 'approve') {\n const body = input.body?.trim();\n await context.api.approveMergeRequest(input.sourceId, mergeRequestIid, input.commitId);\n const comment = body\n ? toPullRequestComment(\n webBaseUrl(context),\n input.sourceId,\n mergeRequestIid,\n await context.api.createMergeRequestNote(input.sourceId, mergeRequestIid, body),\n )\n : null;\n return {\n id: String(mergeRequestIid) + ':approval',\n url: comment?.url ?? mergeRequestUrl(webBaseUrl(context), input.sourceId, mergeRequestIid),\n author: comment?.author ?? null,\n body: comment?.body ?? null,\n state: 'approved',\n commitId: null,\n submittedAt: comment?.createdAt ?? null,\n };\n }\n const body = input.body?.trim();\n if (!body) throw new GitLabApiError('GitLab comment reviews require a body.', 400);\n const note = await context.api.createMergeRequestNote(input.sourceId, mergeRequestIid, body);\n return toCommentReview(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n}\n\nfunction toCommentReview(host: string, sourceId: string, mergeRequestIid: number, note: GitLabNote): Review {\n const comment = toPullRequestComment(host, sourceId, mergeRequestIid, note);\n return {\n id: `${mergeRequestIid}:comment:${note.id}`,\n url: comment.url,\n author: comment.author,\n body: comment.body,\n state: 'commented',\n commitId: null,\n submittedAt: note.created_at,\n };\n}\n\nfunction toApprovalReview(host: string, sourceId: string, mergeRequestIid: number, user: GitLabUser): Review {\n return {\n id: `${mergeRequestIid}:approval:${user.id ?? user.username}`,\n url: mergeRequestUrl(host, sourceId, mergeRequestIid),\n author: displayName(user),\n body: null,\n state: 'approved',\n commitId: null,\n submittedAt: null,\n };\n}\n\nfunction toReviewComment(\n host: string,\n sourceId: string,\n mergeRequestIid: number,\n discussionId: string,\n note: GitLabDiscussionNote,\n replyToId: string | null,\n fallbackPosition?: GitLabDiscussionPosition,\n): ReviewComment {\n const position = note.position ?? fallbackPosition;\n if (!position) throw new GitLabApiError('GitLab review comment is missing its diff position.', 502);\n const base = toPullRequestComment(host, sourceId, mergeRequestIid, note);\n const side = position.new_line !== null && position.new_line !== undefined ? 'right' : 'left';\n return {\n ...base,\n id: packDiscussionNoteId(mergeRequestIid, discussionId, note.id),\n path: side === 'right' ? position.new_path : position.old_path,\n line: side === 'right' ? (position.new_line ?? null) : (position.old_line ?? null),\n side,\n commitId: position.head_sha,\n replyToId,\n };\n}\n\nfunction mergeRequestUrl(host: string, sourceId: string, mergeRequestIid: number): string {\n return `${host}/${sourcePath(sourceId)}/-/merge_requests/${mergeRequestIid}`;\n}\n\nfunction webBaseUrl(context: GitLabVersionControlContext): string {\n const host = normalizeHost(context.host);\n if (!context.webBaseUrl) return `https://${host}`;\n let url: URL;\n try {\n url = new URL(context.webBaseUrl);\n } catch {\n throw new GitLabApiError('GitLab web base URL is invalid.', 400);\n }\n const loopback = url.hostname === 'localhost' || url.hostname === '[::1]' || /^127(?:\\.\\d{1,3}){3}$/.test(url.hostname);\n if (\n url.host !== host ||\n (url.protocol !== 'https:' && !(url.protocol === 'http:' && loopback)) ||\n url.username ||\n url.password ||\n url.search ||\n url.hash\n ) {\n throw new GitLabApiError('GitLab web base URL is invalid.', 400);\n }\n return `${url.origin}${url.pathname.replace(/\\/+$/, '')}`;\n}\n\nfunction sourcePath(sourceId: string): string {\n const match = /^\\d+:(.+)$/.exec(sourceId);\n return normalizeSlug(match?.[1] ?? sourceId);\n}\n\nfunction packDiscussionId(mergeRequestIid: number, discussionId: string): string {\n if (!discussionId || discussionId.includes(':')) {\n throw new GitLabApiError('GitLab discussion id is invalid.', 400);\n }\n return `${mergeRequestIid}:${discussionId}`;\n}\n\nfunction packDiscussionNoteId(mergeRequestIid: number, discussionId: string, noteId: number): string {\n return `${packDiscussionId(mergeRequestIid, discussionId)}:${noteId}`;\n}\n\nfunction parseReviewReplyId(value: string): { mergeRequestIid: number; discussionId: string } {\n const parts = value.split(':');\n if (parts.length === 2) return parseDiscussionId(value);\n if (parts.length === 3 && parts[1]) {\n requirePositiveId(parts[2]!, 'discussion note');\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n discussionId: parts[1],\n };\n }\n throw new GitLabApiError('GitLab review reply id is invalid.', 400);\n}\n\nfunction parseDiscussionId(value: string): { mergeRequestIid: number; discussionId: string } {\n const parts = value.split(':');\n if (parts.length !== 2 || !parts[1]) throw new GitLabApiError('GitLab discussion id is invalid.', 400);\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n discussionId: parts[1],\n };\n}\n\nfunction parseDiscussionNoteId(value: string): { mergeRequestIid: number; discussionId: string; noteId: number } {\n const parts = value.split(':');\n if (parts.length !== 3 || !parts[1]) throw new GitLabApiError('GitLab discussion note id is invalid.', 400);\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n discussionId: parts[1],\n noteId: requirePositiveId(parts[2]!, 'discussion note'),\n };\n}\n\nfunction discussionPosition(notes: GitLabDiscussionNote[]): GitLabDiscussionPosition | undefined {\n return notes.find(note => note.position)?.position ?? undefined;\n}\n\nfunction discussionLine(path: string, line: number, side: 'left' | 'right') {\n const pathHash = createHash('sha1').update(path).digest('hex');\n const oldLine = side === 'left' ? line : undefined;\n const newLine = side === 'right' ? line : undefined;\n return {\n line_code: `${pathHash}_${oldLine ?? 0}_${newLine ?? 0}`,\n type: side === 'left' ? ('old' as const) : ('new' as const),\n old_line: oldLine,\n new_line: newLine,\n };\n}\n\nfunction toRequestedReviewers(mergeRequest: GitLabMergeRequest): RequestedReviewers {\n return {\n users: (mergeRequest.reviewers ?? []).map(user => user.username),\n teams: [],\n };\n}\n\nasync function resolveMembers(api: GitLabApiClient, sourceId: string, usernames: string[]): Promise<GitLabMember[]> {\n return Promise.all(usernames.map(username => resolveMember(api, sourceId, username)));\n}\n\nasync function resolveMember(api: GitLabApiClient, sourceId: string, username: string): Promise<GitLabMember> {\n const normalized = username.trim();\n if (!normalized) throw new GitLabApiError('GitLab reviewer username is invalid.', 400);\n const members = await api.listProjectMembers(sourceId, { query: normalized });\n const member = members.find(candidate => candidate.username.toLowerCase() === normalized.toLowerCase());\n if (!member) throw new GitLabApiError(`GitLab reviewer ${normalized} is not a project member.`, 404);\n return member;\n}\n\nasync function reviewerIds(api: GitLabApiClient, sourceId: string, users: GitLabUser[]): Promise<number[]> {\n return Promise.all(\n users.map(async user => user.id ?? (await resolveMember(api, sourceId, user.username)).id),\n );\n}\n\nfunction rejectTeamReviewers(teams: string[] | undefined): void {\n if (!teams?.length) return;\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab merge requests do not have a direct team-reviewer equivalent.');\n}\n\nfunction notSupported(message: string): GitLabApiError {\n return new GitLabApiError(message, 501);\n}\n\nfunction toPullRequest(mergeRequest: GitLabMergeRequest): PullRequest {\n return {\n id: String(mergeRequest.iid),\n title: mergeRequest.title,\n url: mergeRequest.web_url,\n author: displayName(mergeRequest.author),\n assignees: mergeRequest.assignees?.map(user => user.username),\n requestedReviewers: mergeRequest.reviewers?.map(user => user.username),\n labels: mergeRequest.labels,\n body: mergeRequest.description?.trim() ? mergeRequest.description : null,\n state: mergeRequest.state === 'closed' || mergeRequest.state === 'merged' ? 'closed' : 'open',\n draft: isDraft(mergeRequest),\n merged: mergeRequest.state === 'merged' || Boolean(mergeRequest.merged_at),\n mergeable: mergeableState(mergeRequest.merge_status),\n baseBranch: mergeRequest.target_branch,\n headBranch: mergeRequest.source_branch,\n headSha: mergeRequest.sha,\n createdAt: mergeRequest.created_at,\n updatedAt: mergeRequest.updated_at,\n };\n}\n\nfunction toPullRequestComment(\n host: string,\n sourceId: string,\n mergeRequestIid: number,\n note: GitLabNote,\n): PullRequestComment {\n return {\n id: `${mergeRequestIid}:${note.id}`,\n url: `${mergeRequestUrl(host, sourceId, mergeRequestIid)}#note_${note.id}`,\n author: displayName(note.author),\n body: note.body,\n createdAt: note.created_at,\n updatedAt: note.updated_at ?? note.created_at,\n };\n}\n\nfunction displayName(user: { name?: string | null; username: string } | null | undefined): string | null {\n return user?.username || user?.name?.trim() || null;\n}\n\nfunction isDraft(mergeRequest: GitLabMergeRequest): boolean {\n return mergeRequest.draft ?? mergeRequest.work_in_progress ?? /^(?:draft:|\\[draft\\])/i.test(mergeRequest.title);\n}\n\nfunction mergeableState(status: string | undefined): boolean | null {\n if (status === 'can_be_merged') return true;\n if (status === 'cannot_be_merged') return false;\n return null;\n}\n\nfunction combinedCommitMessage(title: string | undefined, body: string | undefined): string | undefined {\n const parts = [title?.trim(), body?.trim()].filter((part): part is string => Boolean(part));\n return parts.length > 0 ? parts.join('\\n\\n') : undefined;\n}\n\nfunction parseNoteId(value: string): { mergeRequestIid: number; noteId: number } {\n const parts = value.split(':');\n if (parts.length !== 2) throw new GitLabApiError('GitLab merge request note id is invalid.', 400);\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n noteId: requirePositiveId(parts[1]!, 'note'),\n };\n}\n\nfunction parsePositiveCursor(cursor: string | undefined): number {\n if (cursor === undefined) return 1;\n const page = parsePositiveInteger(cursor);\n if (page === null) throw new GitLabApiError('GitLab cursor must be a positive page number.', 400);\n return page;\n}\n\nfunction requirePositiveId(value: string, resource: string): number {\n const parsed = parsePositiveInteger(value);\n if (parsed === null) throw new GitLabApiError(`GitLab ${resource} id must be a positive integer.`, 400);\n return parsed;\n}\n\nfunction parsePositiveInteger(value: string): number | null {\n if (!/^\\d+$/.test(value)) return null;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction parseConnection(value: unknown): IntegrationConnection | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n const connection = value as Record<string, unknown>;\n if (connection.type === 'oauth' && typeof connection.accessToken === 'string' && connection.accessToken.length > 0) {\n return { type: 'oauth', accessToken: connection.accessToken };\n }\n if (\n connection.type === 'app-installation' &&\n Number.isSafeInteger(connection.installationId) &&\n Number(connection.installationId) > 0\n ) {\n return { type: 'app-installation', installationId: Number(connection.installationId) };\n }\n return null;\n}\n\nfunction normalizeHost(value: string): string {\n const host = value.trim();\n if (!host || host.includes('/') || host.includes('@')) throw new GitLabApiError('GitLab host is invalid.', 400);\n let parsed: URL;\n try {\n parsed = new URL(`https://${host}`);\n } catch {\n throw new GitLabApiError('GitLab host is invalid.', 400);\n }\n if (parsed.host !== host) throw new GitLabApiError('GitLab host is invalid.', 400);\n return host;\n}\n\nfunction normalizeSlug(value: string): string {\n const slug = value.replace(/^\\/+|\\/+$/g, '');\n const segments = slug.split('/');\n if (!slug || segments.some(segment => !/^[A-Za-z0-9_.-]+$/.test(segment) || segment === '.' || segment === '..')) {\n throw new GitLabApiError('GitLab repository slug is invalid.', 400);\n }\n return slug;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"version-control.js","names":[],"sources":["../../../src/integrations/gitlab/version-control.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nimport type { IntegrationConnection } from '../../capabilities/connection.js';\nimport type {\n PullRequest,\n PullRequestComment,\n RequestedReviewers,\n Review,\n ReviewComment,\n VersionControl,\n} from '../../capabilities/version-control.js';\nimport type { SourceControlStorageHandle } from '../../storage/domains/source-control/base.js';\nimport {\n GITLAB_DISCUSSIONS_PAGE_SIZE,\n GITLAB_MERGE_REQUESTS_PAGE_SIZE,\n GITLAB_NOTES_PAGE_SIZE,\n GitLabApiError,\n} from './api.js';\nimport type {\n GitLabApiClient,\n GitLabDiscussionNote,\n GitLabDiscussionPosition,\n GitLabMember,\n GitLabMergeRequest,\n GitLabNote,\n GitLabUser,\n} from './api.js';\n\nexport interface GitLabVersionControlContext {\n api: GitLabApiClient;\n connection: IntegrationConnection;\n host: string;\n webBaseUrl?: string;\n repositoryAccessToken?: () => Promise<string>;\n}\n\nexport interface GitLabVersionControlDependencies {\n contextForConnection(connection: IntegrationConnection): Promise<GitLabVersionControlContext>;\n contextForStoredInstallation?(\n connection: IntegrationConnection,\n host: string | undefined,\n ): Promise<GitLabVersionControlContext>;\n}\n\nexport function buildGitLabVersionControl(deps: GitLabVersionControlDependencies): VersionControl {\n let storage: SourceControlStorageHandle | undefined;\n\n const sourceControlStorage = (): SourceControlStorageHandle => {\n if (!storage) throw new Error('GitLab VersionControl is not initialized.');\n return storage;\n };\n\n const listPullRequests: VersionControl['listPullRequests'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const page = parsePositiveCursor(input.cursor);\n const state = input.state === 'open' ? 'opened' : input.state === 'closed' ? 'all' : (input.state ?? 'opened');\n const mergeRequests = await context.api.listMergeRequests(input.sourceId, { page, state });\n return {\n pullRequests: mergeRequests\n .filter(\n mergeRequest =>\n input.state !== 'closed' || mergeRequest.state === 'closed' || mergeRequest.state === 'merged',\n )\n .filter(mergeRequest => input.includeDrafts !== false || !isDraft(mergeRequest))\n .map(toPullRequest),\n nextCursor: mergeRequests.length === GITLAB_MERGE_REQUESTS_PAGE_SIZE ? String(page + 1) : null,\n };\n };\n\n const getPullRequest: VersionControl['getPullRequest'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n try {\n return toPullRequest(\n await context.api.getMergeRequest(input.sourceId, requirePositiveId(input.pullRequestId, 'merge request')),\n );\n } catch (error) {\n if (error instanceof GitLabApiError && error.status === 404) return null;\n throw error;\n }\n };\n\n const createPullRequest: VersionControl['createPullRequest'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const title = input.draft && !/^(?:draft:|\\[draft\\])/i.test(input.title) ? `Draft: ${input.title}` : input.title;\n return toPullRequest(\n await context.api.createMergeRequest(input.sourceId, {\n sourceBranch: input.headBranch,\n targetBranch: input.baseBranch,\n title,\n description: input.body,\n }),\n );\n };\n\n const updatePullRequest: VersionControl['updatePullRequest'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n return toPullRequest(\n await context.api.updateMergeRequest(input.sourceId, requirePositiveId(input.pullRequestId, 'merge request'), {\n title: input.title,\n description: input.body === null ? '' : input.body,\n targetBranch: input.baseBranch,\n stateEvent: input.state === 'closed' ? 'close' : input.state === 'open' ? 'reopen' : undefined,\n }),\n );\n };\n\n const closePullRequest: VersionControl['closePullRequest'] = input =>\n updatePullRequest({ ...input, state: 'closed' });\n\n const mergePullRequest: VersionControl['mergePullRequest'] = async input => {\n if (input.method === 'rebase') {\n throw notSupported('GitLab rebases merge requests asynchronously; rebase-and-merge is not supported.');\n }\n const context = await deps.contextForConnection(input.connection);\n const commitMessage = combinedCommitMessage(input.commitTitle, input.commitMessage);\n const result = await context.api.mergeMergeRequest(\n input.sourceId,\n requirePositiveId(input.pullRequestId, 'merge request'),\n {\n squash: input.method === 'squash',\n mergeCommitMessage: input.method === 'squash' ? undefined : commitMessage,\n squashCommitMessage: input.method === 'squash' ? commitMessage : undefined,\n },\n );\n const merged = result.state === 'merged' || Boolean(result.merged_at);\n return {\n merged,\n message: result.message ?? (merged ? 'Merge request merged.' : 'Merge request was not merged.'),\n sha: result.squash_commit_sha ?? result.merge_commit_sha ?? result.sha ?? null,\n };\n };\n\n const listComments: VersionControl['listComments'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const page = parsePositiveCursor(input.cursor);\n const notes = await context.api.listMergeRequestNotes(input.sourceId, mergeRequestIid, { page });\n return {\n comments: notes\n .filter(note => !note.system && note.type !== 'DiffNote')\n .map(note => toPullRequestComment(webBaseUrl(context), input.sourceId, mergeRequestIid, note)),\n nextCursor: notes.length === GITLAB_NOTES_PAGE_SIZE ? String(page + 1) : null,\n };\n };\n\n const createComment: VersionControl['createComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const note = await context.api.createMergeRequestNote(input.sourceId, mergeRequestIid, input.body);\n return toPullRequestComment(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n };\n\n const updateComment: VersionControl['updateComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const { mergeRequestIid, noteId } = parseNoteId(input.commentId);\n const note = await context.api.updateMergeRequestNote(input.sourceId, mergeRequestIid, noteId, input.body);\n return toPullRequestComment(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n };\n\n const deleteComment: VersionControl['deleteComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const { mergeRequestIid, noteId } = parseNoteId(input.commentId);\n await context.api.deleteMergeRequestNote(input.sourceId, mergeRequestIid, noteId);\n };\n\n const listReviews: VersionControl['listReviews'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const approvals = await context.api.getMergeRequestApprovals(input.sourceId, mergeRequestIid);\n return {\n reviews: (approvals.approved_by ?? []).map(({ user }) =>\n toApprovalReview(webBaseUrl(context), input.sourceId, mergeRequestIid, user),\n ),\n nextCursor: null,\n };\n };\n\n const getReview: VersionControl['getReview'] = async input => {\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const approvalPrefix = `${mergeRequestIid}:approval`;\n const commentPrefix = `${mergeRequestIid}:comment:`;\n if (\n input.reviewId !== approvalPrefix &&\n !input.reviewId.startsWith(`${approvalPrefix}:`) &&\n !input.reviewId.startsWith(commentPrefix)\n ) {\n return null;\n }\n const context = await deps.contextForConnection(input.connection);\n if (input.reviewId === approvalPrefix || input.reviewId.startsWith(`${approvalPrefix}:`)) {\n const reviewerKey = input.reviewId === approvalPrefix ? null : input.reviewId.slice(approvalPrefix.length + 1);\n if (reviewerKey === '') return null;\n const currentUser = reviewerKey === null ? await context.api.getCurrentUser() : null;\n const approvals = await context.api.getMergeRequestApprovals(input.sourceId, mergeRequestIid);\n const user = (approvals.approved_by ?? [])\n .map(entry => entry.user)\n .find(candidate =>\n reviewerKey === null\n ? (currentUser?.id !== undefined && candidate.id === currentUser.id) ||\n candidate.username === currentUser?.username\n : String(candidate.id ?? candidate.username) === reviewerKey,\n );\n return user ? toApprovalReview(webBaseUrl(context), input.sourceId, mergeRequestIid, user) : null;\n }\n const noteId = parsePositiveInteger(input.reviewId.slice(commentPrefix.length));\n if (noteId === null) return null;\n try {\n const note = await context.api.getMergeRequestNote(input.sourceId, mergeRequestIid, noteId);\n if (note.system || note.type === 'DiffNote') return null;\n return toCommentReview(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n } catch (error) {\n if (error instanceof GitLabApiError && error.status === 404) return null;\n throw error;\n }\n };\n\n const createReview: VersionControl['createReview'] = async input =>\n submitReviewAction(deps, {\n connection: input.connection,\n sourceId: input.sourceId,\n pullRequestId: input.pullRequestId,\n event: input.event,\n body: input.body,\n commitId: input.commitId,\n });\n\n const updateReview: VersionControl['updateReview'] = async () => {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab does not expose mutable pending review objects.');\n };\n\n const submitReview: VersionControl['submitReview'] = async input =>\n submitReviewAction(deps, {\n connection: input.connection,\n sourceId: input.sourceId,\n pullRequestId: input.pullRequestId,\n event: input.event,\n body: input.body,\n });\n\n const dismissReview: VersionControl['dismissReview'] = async () => {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab approval dismissal has no GitHub review equivalent.');\n };\n\n const deletePendingReview: VersionControl['deletePendingReview'] = async () => {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab does not expose pending review objects.');\n };\n\n const listReviewComments: VersionControl['listReviewComments'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const page = parsePositiveCursor(input.cursor);\n const discussions = await context.api.listMergeRequestDiscussions(input.sourceId, mergeRequestIid, { page });\n return {\n comments: discussions.flatMap(discussion => {\n const position = discussionPosition(discussion.notes);\n if (!position) return [];\n const root = discussion.notes.find(note => note.position) ?? discussion.notes[0];\n const replyToId = root ? packDiscussionNoteId(mergeRequestIid, discussion.id, root.id) : null;\n return discussion.notes\n .filter(note => !note.system)\n .map(note =>\n toReviewComment(\n webBaseUrl(context),\n input.sourceId,\n mergeRequestIid,\n discussion.id,\n note,\n note === root ? null : replyToId,\n position,\n ),\n );\n }),\n nextCursor: discussions.length === GITLAB_DISCUSSIONS_PAGE_SIZE ? String(page + 1) : null,\n };\n };\n\n const createReviewComment: VersionControl['createReviewComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n if (input.replyToId) {\n const thread = parseReviewReplyId(input.replyToId);\n if (thread.mergeRequestIid !== mergeRequestIid) {\n throw new GitLabApiError('GitLab discussion does not belong to the requested merge request.', 400);\n }\n const discussion = await context.api.getMergeRequestDiscussion(\n input.sourceId,\n mergeRequestIid,\n thread.discussionId,\n );\n const position = discussionPosition(discussion.notes);\n if (!position) throw new GitLabApiError('GitLab discussion is not anchored to a diff.', 400);\n const root = discussion.notes.find(note => note.position) ?? discussion.notes[0];\n if (!root) throw new GitLabApiError('GitLab discussion response did not include a note.', 502);\n const note = await context.api.addMergeRequestDiscussionNote(\n input.sourceId,\n mergeRequestIid,\n thread.discussionId,\n input.body,\n );\n return toReviewComment(\n webBaseUrl(context),\n input.sourceId,\n mergeRequestIid,\n thread.discussionId,\n note,\n packDiscussionNoteId(mergeRequestIid, thread.discussionId, root.id),\n position,\n );\n }\n\n const mergeRequest = await context.api.getMergeRequest(input.sourceId, mergeRequestIid);\n if (!mergeRequest.diff_refs) {\n throw new GitLabApiError('GitLab merge request diff refs are not ready.', 409);\n }\n if (mergeRequest.diff_refs.head_sha !== input.commitId) {\n throw new GitLabApiError('GitLab merge request changed since this review comment was prepared.', 409);\n }\n const { path, line, side } = input;\n if (typeof path !== 'string' || typeof line !== 'number' || (side !== 'left' && side !== 'right')) {\n throw new GitLabApiError('GitLab diff review comment position is invalid.', 400);\n }\n if ((input.startLine === undefined) !== (input.startSide === undefined)) {\n throw new GitLabApiError('A multi-line GitLab review comment requires both startLine and startSide.', 400);\n }\n const position: GitLabDiscussionPosition = {\n position_type: 'text',\n ...mergeRequest.diff_refs,\n old_path: path,\n new_path: path,\n old_line: side === 'left' ? line : undefined,\n new_line: side === 'right' ? line : undefined,\n ...(input.startLine !== undefined && input.startSide\n ? {\n line_range: {\n start: discussionLine(path, input.startLine, input.startSide),\n end: discussionLine(path, line, side),\n },\n }\n : {}),\n };\n const discussion = await context.api.createMergeRequestDiscussion(input.sourceId, mergeRequestIid, {\n body: input.body,\n commitId: input.commitId,\n position,\n });\n const note = discussion.notes.find(candidate => candidate.position) ?? discussion.notes[0];\n if (!note) throw new GitLabApiError('GitLab discussion response did not include a note.', 502);\n return toReviewComment(webBaseUrl(context), input.sourceId, mergeRequestIid, discussion.id, note, null, position);\n };\n\n const updateReviewComment: VersionControl['updateReviewComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const reference = parseDiscussionNoteId(input.commentId);\n const discussion = await context.api.getMergeRequestDiscussion(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n );\n const position = discussionPosition(discussion.notes);\n if (!position) throw new GitLabApiError('GitLab discussion is not anchored to a diff.', 400);\n const root = discussion.notes.find(candidate => candidate.position) ?? discussion.notes[0];\n if (!root) throw new GitLabApiError('GitLab discussion response did not include a note.', 502);\n const note = await context.api.updateMergeRequestDiscussionNote(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n reference.noteId,\n input.body,\n );\n return toReviewComment(\n webBaseUrl(context),\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n note,\n note.id === root.id ? null : packDiscussionNoteId(reference.mergeRequestIid, reference.discussionId, root.id),\n position,\n );\n };\n\n const deleteReviewComment: VersionControl['deleteReviewComment'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const reference = parseDiscussionNoteId(input.commentId);\n await context.api.deleteMergeRequestDiscussionNote(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n reference.noteId,\n );\n };\n\n const resolveReviewThread: NonNullable<VersionControl['resolveReviewThread']> = async input => {\n const context = await deps.contextForConnection(input.connection);\n const reference = parseDiscussionNoteId(input.commentId);\n await context.api.resolveMergeRequestDiscussion(\n input.sourceId,\n reference.mergeRequestIid,\n reference.discussionId,\n input.resolved,\n );\n };\n\n const listRequestedReviewers: VersionControl['listRequestedReviewers'] = async input => {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequest = await context.api.getMergeRequest(\n input.sourceId,\n requirePositiveId(input.pullRequestId, 'merge request'),\n );\n return toRequestedReviewers(mergeRequest);\n };\n\n const requestReviewers: VersionControl['requestReviewers'] = async input => {\n rejectTeamReviewers(input.teams);\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const mergeRequest = await context.api.getMergeRequest(input.sourceId, mergeRequestIid);\n const requestedMembers = await resolveMembers(context.api, input.sourceId, input.users ?? []);\n const currentIds = await reviewerIds(context.api, input.sourceId, mergeRequest.reviewers ?? []);\n const reviewerIdsToSet = [...new Set([...currentIds, ...requestedMembers.map(member => member.id)])];\n return toRequestedReviewers(\n await context.api.setMergeRequestReviewers(input.sourceId, mergeRequestIid, reviewerIdsToSet),\n );\n };\n\n const removeRequestedReviewers: VersionControl['removeRequestedReviewers'] = async input => {\n rejectTeamReviewers(input.teams);\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n const mergeRequest = await context.api.getMergeRequest(input.sourceId, mergeRequestIid);\n const removals = new Set((input.users ?? []).map(username => username.toLowerCase()));\n const retained = (mergeRequest.reviewers ?? []).filter(user => !removals.has(user.username.toLowerCase()));\n const retainedIds = await reviewerIds(context.api, input.sourceId, retained);\n return toRequestedReviewers(\n await context.api.setMergeRequestReviewers(input.sourceId, mergeRequestIid, retainedIds),\n );\n };\n\n return {\n initialize: input => {\n storage = input.storage;\n },\n registerInstallation: async ({ orgId, userId, installation }) => {\n const requestedConnection = parseConnection(installation.metadata?.connection);\n if (!requestedConnection) {\n throw new GitLabApiError('GitLab installation metadata must include a valid connection.', 400);\n }\n const context = await deps.contextForConnection(requestedConnection);\n return sourceControlStorage().installations.upsert({\n orgId,\n connectedByUserId: userId,\n externalId: installation.externalId,\n accountName: installation.accountName,\n accountType: installation.accountType,\n providerMetadata: {\n ...installation.metadata,\n connection: context.connection,\n host: normalizeHost(context.host),\n },\n });\n },\n registerRepositories: async ({ orgId, installationId, repositories }) => {\n const normalizedRepositories = repositories.map(repository => ({\n ...repository,\n slug: normalizeSlug(repository.slug),\n }));\n return await Promise.all(\n normalizedRepositories.map(repository =>\n sourceControlStorage().repositories.upsert({\n orgId,\n input: {\n installationId,\n externalId: repository.externalId,\n slug: repository.slug,\n defaultBranch: repository.defaultBranch,\n providerMetadata: repository.metadata,\n },\n }),\n ),\n );\n },\n getRepositoryTarget: async ({ orgId, repositoryId }) => {\n const repository = await sourceControlStorage().repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const installation = await sourceControlStorage().installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) throw new Error('Version-control installation not found.');\n const connection = parseConnection(installation.providerMetadata.connection);\n if (!connection) throw new GitLabApiError('GitLab installation connection metadata is invalid.', 500);\n const context = await (deps.contextForStoredInstallation ?? deps.contextForConnection)(\n connection,\n typeof installation.providerMetadata.host === 'string' ? installation.providerMetadata.host : undefined,\n );\n // The API uses GitLab's immutable numeric project ID because Platform's\n // proxy normalizes encoded path slashes; retain the slug for browser URLs.\n return { connection: context.connection, sourceId: `${repository.externalId}:${repository.slug}` };\n },\n getRepositoryAccess: async ({ orgId, repositoryId }) => {\n const repository = await sourceControlStorage().repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const installation = await sourceControlStorage().installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) throw new Error('Version-control installation not found.');\n const connection = parseConnection(installation.providerMetadata.connection);\n if (!connection) throw new GitLabApiError('GitLab installation connection metadata is invalid.', 500);\n const context = await (deps.contextForStoredInstallation ?? deps.contextForConnection)(\n connection,\n typeof installation.providerMetadata.host === 'string' ? installation.providerMetadata.host : undefined,\n );\n if (!context.repositoryAccessToken) {\n throw notSupported('This GitLab connection does not expose credentials for repository cloning.');\n }\n const token = await context.repositoryAccessToken();\n const baseUrl = webBaseUrl(context);\n const slug = normalizeSlug(repository.slug);\n return {\n cloneUrl: `${baseUrl}/${slug}.git`,\n authorization: { scheme: 'bearer', token, username: 'oauth2' },\n };\n },\n listPullRequests,\n getPullRequest,\n createPullRequest,\n updatePullRequest,\n closePullRequest,\n mergePullRequest,\n listComments,\n resolveReviewThread,\n createComment,\n updateComment,\n deleteComment,\n listReviews,\n getReview,\n createReview,\n updateReview,\n submitReview,\n dismissReview,\n deletePendingReview,\n listReviewComments,\n createReviewComment,\n updateReviewComment,\n deleteReviewComment,\n listRequestedReviewers,\n requestReviewers,\n removeRequestedReviewers,\n };\n}\n\nasync function submitReviewAction(\n deps: GitLabVersionControlDependencies,\n input: {\n connection: IntegrationConnection;\n sourceId: string;\n pullRequestId: string;\n event: 'approve' | 'request-changes' | 'comment' | undefined;\n body?: string;\n commitId?: string;\n },\n): Promise<Review> {\n const context = await deps.contextForConnection(input.connection);\n const mergeRequestIid = requirePositiveId(input.pullRequestId, 'merge request');\n if (input.event === 'request-changes') {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab has no first-class request-changes review event.');\n }\n if (input.event === undefined) {\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab has no first-class pending review object.');\n }\n if (input.event === 'approve') {\n const body = input.body?.trim();\n await context.api.approveMergeRequest(input.sourceId, mergeRequestIid, input.commitId);\n const comment = body\n ? toPullRequestComment(\n webBaseUrl(context),\n input.sourceId,\n mergeRequestIid,\n await context.api.createMergeRequestNote(input.sourceId, mergeRequestIid, body),\n )\n : null;\n return {\n id: String(mergeRequestIid) + ':approval',\n url: comment?.url ?? mergeRequestUrl(webBaseUrl(context), input.sourceId, mergeRequestIid),\n author: comment?.author ?? null,\n body: comment?.body ?? null,\n state: 'approved',\n commitId: null,\n submittedAt: comment?.createdAt ?? null,\n };\n }\n const body = input.body?.trim();\n if (!body) throw new GitLabApiError('GitLab comment reviews require a body.', 400);\n const note = await context.api.createMergeRequestNote(input.sourceId, mergeRequestIid, body);\n return toCommentReview(webBaseUrl(context), input.sourceId, mergeRequestIid, note);\n}\n\nfunction toCommentReview(host: string, sourceId: string, mergeRequestIid: number, note: GitLabNote): Review {\n const comment = toPullRequestComment(host, sourceId, mergeRequestIid, note);\n return {\n id: `${mergeRequestIid}:comment:${note.id}`,\n url: comment.url,\n author: comment.author,\n body: comment.body,\n state: 'commented',\n commitId: null,\n submittedAt: note.created_at,\n };\n}\n\nfunction toApprovalReview(host: string, sourceId: string, mergeRequestIid: number, user: GitLabUser): Review {\n return {\n id: `${mergeRequestIid}:approval:${user.id ?? user.username}`,\n url: mergeRequestUrl(host, sourceId, mergeRequestIid),\n author: displayName(user),\n body: null,\n state: 'approved',\n commitId: null,\n submittedAt: null,\n };\n}\n\nfunction toReviewComment(\n host: string,\n sourceId: string,\n mergeRequestIid: number,\n discussionId: string,\n note: GitLabDiscussionNote,\n replyToId: string | null,\n fallbackPosition?: GitLabDiscussionPosition,\n): ReviewComment {\n const position = note.position ?? fallbackPosition;\n if (!position) throw new GitLabApiError('GitLab review comment is missing its diff position.', 502);\n const base = toPullRequestComment(host, sourceId, mergeRequestIid, note);\n const side = position.new_line !== null && position.new_line !== undefined ? 'right' : 'left';\n return {\n ...base,\n id: packDiscussionNoteId(mergeRequestIid, discussionId, note.id),\n path: side === 'right' ? position.new_path : position.old_path,\n line: side === 'right' ? (position.new_line ?? null) : (position.old_line ?? null),\n side,\n commitId: position.head_sha,\n replyToId,\n };\n}\n\nfunction mergeRequestUrl(host: string, sourceId: string, mergeRequestIid: number): string {\n return `${host}/${sourcePath(sourceId)}/-/merge_requests/${mergeRequestIid}`;\n}\n\nfunction webBaseUrl(context: GitLabVersionControlContext): string {\n const host = normalizeHost(context.host);\n if (!context.webBaseUrl) return `https://${host}`;\n let url: URL;\n try {\n url = new URL(context.webBaseUrl);\n } catch {\n throw new GitLabApiError('GitLab web base URL is invalid.', 400);\n }\n const loopback =\n url.hostname === 'localhost' || url.hostname === '[::1]' || /^127(?:\\.\\d{1,3}){3}$/.test(url.hostname);\n if (\n url.host !== host ||\n (url.protocol !== 'https:' && !(url.protocol === 'http:' && loopback)) ||\n url.username ||\n url.password ||\n url.search ||\n url.hash\n ) {\n throw new GitLabApiError('GitLab web base URL is invalid.', 400);\n }\n return `${url.origin}${url.pathname.replace(/\\/+$/, '')}`;\n}\n\nfunction sourcePath(sourceId: string): string {\n const match = /^\\d+:(.+)$/.exec(sourceId);\n return normalizeSlug(match?.[1] ?? sourceId);\n}\n\nfunction packDiscussionId(mergeRequestIid: number, discussionId: string): string {\n if (!discussionId || discussionId.includes(':')) {\n throw new GitLabApiError('GitLab discussion id is invalid.', 400);\n }\n return `${mergeRequestIid}:${discussionId}`;\n}\n\nfunction packDiscussionNoteId(mergeRequestIid: number, discussionId: string, noteId: number): string {\n return `${packDiscussionId(mergeRequestIid, discussionId)}:${noteId}`;\n}\n\nfunction parseReviewReplyId(value: string): { mergeRequestIid: number; discussionId: string } {\n const parts = value.split(':');\n if (parts.length === 2) return parseDiscussionId(value);\n if (parts.length === 3 && parts[1]) {\n requirePositiveId(parts[2]!, 'discussion note');\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n discussionId: parts[1],\n };\n }\n throw new GitLabApiError('GitLab review reply id is invalid.', 400);\n}\n\nfunction parseDiscussionId(value: string): { mergeRequestIid: number; discussionId: string } {\n const parts = value.split(':');\n if (parts.length !== 2 || !parts[1]) throw new GitLabApiError('GitLab discussion id is invalid.', 400);\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n discussionId: parts[1],\n };\n}\n\nfunction parseDiscussionNoteId(value: string): { mergeRequestIid: number; discussionId: string; noteId: number } {\n const parts = value.split(':');\n if (parts.length !== 3 || !parts[1]) throw new GitLabApiError('GitLab discussion note id is invalid.', 400);\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n discussionId: parts[1],\n noteId: requirePositiveId(parts[2]!, 'discussion note'),\n };\n}\n\nfunction discussionPosition(notes: GitLabDiscussionNote[]): GitLabDiscussionPosition | undefined {\n return notes.find(note => note.position)?.position ?? undefined;\n}\n\nfunction discussionLine(path: string, line: number, side: 'left' | 'right') {\n const pathHash = createHash('sha1').update(path).digest('hex');\n const oldLine = side === 'left' ? line : undefined;\n const newLine = side === 'right' ? line : undefined;\n return {\n line_code: `${pathHash}_${oldLine ?? 0}_${newLine ?? 0}`,\n type: side === 'left' ? ('old' as const) : ('new' as const),\n old_line: oldLine,\n new_line: newLine,\n };\n}\n\nfunction toRequestedReviewers(mergeRequest: GitLabMergeRequest): RequestedReviewers {\n return {\n users: (mergeRequest.reviewers ?? []).map(user => user.username),\n teams: [],\n };\n}\n\nasync function resolveMembers(api: GitLabApiClient, sourceId: string, usernames: string[]): Promise<GitLabMember[]> {\n return Promise.all(usernames.map(username => resolveMember(api, sourceId, username)));\n}\n\nasync function resolveMember(api: GitLabApiClient, sourceId: string, username: string): Promise<GitLabMember> {\n const normalized = username.trim();\n if (!normalized) throw new GitLabApiError('GitLab reviewer username is invalid.', 400);\n const members = await api.listProjectMembers(sourceId, { query: normalized });\n const member = members.find(candidate => candidate.username.toLowerCase() === normalized.toLowerCase());\n if (!member) throw new GitLabApiError(`GitLab reviewer ${normalized} is not a project member.`, 404);\n return member;\n}\n\nasync function reviewerIds(api: GitLabApiClient, sourceId: string, users: GitLabUser[]): Promise<number[]> {\n return Promise.all(users.map(async user => user.id ?? (await resolveMember(api, sourceId, user.username)).id));\n}\n\nfunction rejectTeamReviewers(teams: string[] | undefined): void {\n if (!teams?.length) return;\n // FLAGGED FOR MANUAL REVIEW (spec §6.2)\n throw notSupported('GitLab merge requests do not have a direct team-reviewer equivalent.');\n}\n\nfunction notSupported(message: string): GitLabApiError {\n return new GitLabApiError(message, 501);\n}\n\nfunction toPullRequest(mergeRequest: GitLabMergeRequest): PullRequest {\n return {\n id: String(mergeRequest.iid),\n title: mergeRequest.title,\n url: mergeRequest.web_url,\n author: displayName(mergeRequest.author),\n assignees: mergeRequest.assignees?.map(user => user.username),\n requestedReviewers: mergeRequest.reviewers?.map(user => user.username),\n labels: mergeRequest.labels,\n body: mergeRequest.description?.trim() ? mergeRequest.description : null,\n state: mergeRequest.state === 'closed' || mergeRequest.state === 'merged' ? 'closed' : 'open',\n draft: isDraft(mergeRequest),\n merged: mergeRequest.state === 'merged' || Boolean(mergeRequest.merged_at),\n mergeable: mergeableState(mergeRequest.merge_status),\n baseBranch: mergeRequest.target_branch,\n headBranch: mergeRequest.source_branch,\n headSha: mergeRequest.sha,\n createdAt: mergeRequest.created_at,\n updatedAt: mergeRequest.updated_at,\n };\n}\n\nfunction toPullRequestComment(\n host: string,\n sourceId: string,\n mergeRequestIid: number,\n note: GitLabNote,\n): PullRequestComment {\n return {\n id: `${mergeRequestIid}:${note.id}`,\n url: `${mergeRequestUrl(host, sourceId, mergeRequestIid)}#note_${note.id}`,\n author: displayName(note.author),\n body: note.body,\n createdAt: note.created_at,\n updatedAt: note.updated_at ?? note.created_at,\n };\n}\n\nfunction displayName(user: { name?: string | null; username: string } | null | undefined): string | null {\n return user?.username || user?.name?.trim() || null;\n}\n\nfunction isDraft(mergeRequest: GitLabMergeRequest): boolean {\n return mergeRequest.draft ?? mergeRequest.work_in_progress ?? /^(?:draft:|\\[draft\\])/i.test(mergeRequest.title);\n}\n\nfunction mergeableState(status: string | undefined): boolean | null {\n if (status === 'can_be_merged') return true;\n if (status === 'cannot_be_merged') return false;\n return null;\n}\n\nfunction combinedCommitMessage(title: string | undefined, body: string | undefined): string | undefined {\n const parts = [title?.trim(), body?.trim()].filter((part): part is string => Boolean(part));\n return parts.length > 0 ? parts.join('\\n\\n') : undefined;\n}\n\nfunction parseNoteId(value: string): { mergeRequestIid: number; noteId: number } {\n const parts = value.split(':');\n if (parts.length !== 2) throw new GitLabApiError('GitLab merge request note id is invalid.', 400);\n return {\n mergeRequestIid: requirePositiveId(parts[0]!, 'merge request'),\n noteId: requirePositiveId(parts[1]!, 'note'),\n };\n}\n\nfunction parsePositiveCursor(cursor: string | undefined): number {\n if (cursor === undefined) return 1;\n const page = parsePositiveInteger(cursor);\n if (page === null) throw new GitLabApiError('GitLab cursor must be a positive page number.', 400);\n return page;\n}\n\nfunction requirePositiveId(value: string, resource: string): number {\n const parsed = parsePositiveInteger(value);\n if (parsed === null) throw new GitLabApiError(`GitLab ${resource} id must be a positive integer.`, 400);\n return parsed;\n}\n\nfunction parsePositiveInteger(value: string): number | null {\n if (!/^\\d+$/.test(value)) return null;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction parseConnection(value: unknown): IntegrationConnection | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n const connection = value as Record<string, unknown>;\n if (connection.type === 'oauth' && typeof connection.accessToken === 'string' && connection.accessToken.length > 0) {\n return { type: 'oauth', accessToken: connection.accessToken };\n }\n if (\n connection.type === 'app-installation' &&\n Number.isSafeInteger(connection.installationId) &&\n Number(connection.installationId) > 0\n ) {\n return { type: 'app-installation', installationId: Number(connection.installationId) };\n }\n return null;\n}\n\nfunction normalizeHost(value: string): string {\n const host = value.trim();\n if (!host || host.includes('/') || host.includes('@')) throw new GitLabApiError('GitLab host is invalid.', 400);\n let parsed: URL;\n try {\n parsed = new URL(`https://${host}`);\n } catch {\n throw new GitLabApiError('GitLab host is invalid.', 400);\n }\n if (parsed.host !== host) throw new GitLabApiError('GitLab host is invalid.', 400);\n return host;\n}\n\nfunction normalizeSlug(value: string): string {\n const slug = value.replace(/^\\/+|\\/+$/g, '');\n const segments = slug.split('/');\n if (!slug || segments.some(segment => !/^[A-Za-z0-9_.-]+$/.test(segment) || segment === '.' || segment === '..')) {\n throw new GitLabApiError('GitLab repository slug is invalid.', 400);\n }\n return slug;\n}\n"],"mappings":"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"}
|