@cat-factory/gitlab 0.1.2 → 0.1.3
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/LICENSE +21 -21
- package/dist/FetchGitLabClient.d.ts +77 -0
- package/dist/FetchGitLabClient.d.ts.map +1 -0
- package/dist/FetchGitLabClient.js +435 -0
- package/dist/FetchGitLabClient.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/projection.d.ts +102 -0
- package/dist/projection.d.ts.map +1 -0
- package/dist/projection.js +173 -0
- package/dist/projection.js.map +1 -0
- package/dist/provisioning.d.ts +16 -0
- package/dist/provisioning.d.ts.map +1 -0
- package/dist/provisioning.js +73 -0
- package/dist/provisioning.js.map +1 -0
- package/dist/tokenSource.d.ts +25 -0
- package/dist/tokenSource.d.ts.map +1 -0
- package/dist/tokenSource.js +21 -0
- package/dist/tokenSource.js.map +1 -0
- package/dist/webhook.d.ts +17 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +183 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +2 -2
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { registerVcsProvider } from '@cat-factory/kernel';
|
|
2
|
+
import { FetchGitLabClient } from './FetchGitLabClient.js';
|
|
3
|
+
import { GitLabProvisioningClient } from './provisioning.js';
|
|
4
|
+
import { GitLabWebhookMapper, GitLabWebhookVerifier } from './webhook.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// The GitLab VCS provider, authored entirely through the public VCS-registry seam
|
|
7
|
+
// (`registerVcsProvider`) — depending only on @cat-factory/kernel + @cat-factory/contracts,
|
|
8
|
+
// never on the engine or a runtime facade. A deployment that wants GitLab support calls
|
|
9
|
+
// `registerGitLab(...)` once at startup; any caller holding a `gitlab` VcsConnectionRef then
|
|
10
|
+
// resolves this bundle via `resolveVcsProvider(ref)`.
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
export { FetchGitLabClient, GitLabApiError } from './FetchGitLabClient.js';
|
|
13
|
+
export { GitLabProvisioningClient } from './provisioning.js';
|
|
14
|
+
export { GitLabWebhookMapper, GitLabWebhookVerifier } from './webhook.js';
|
|
15
|
+
export { StaticGitLabTokenSource, GITLAB_PUBLIC_API_BASE, } from './tokenSource.js';
|
|
16
|
+
export * as gitlabProjection from './projection.js';
|
|
17
|
+
/**
|
|
18
|
+
* Register the GitLab provider bundle (client + webhook verifier/mapper + provisioning)
|
|
19
|
+
* in the process-wide VCS registry. Call once at startup. Idempotent — a later call
|
|
20
|
+
* replaces the earlier registration.
|
|
21
|
+
*/
|
|
22
|
+
export function registerGitLab(options) {
|
|
23
|
+
const { tokenSource, clock, webhookSecret, fetchImpl, logger } = options;
|
|
24
|
+
registerVcsProvider({
|
|
25
|
+
provider: 'gitlab',
|
|
26
|
+
client: new FetchGitLabClient({ tokenSource, clock, fetchImpl, logger }),
|
|
27
|
+
webhookMapper: new GitLabWebhookMapper(clock),
|
|
28
|
+
webhookVerifier: webhookSecret ? new GitLabWebhookVerifier(webhookSecret) : undefined,
|
|
29
|
+
provisioning: new GitLabProvisioningClient({ tokenSource, fetchImpl }),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAc,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAGzE,8EAA8E;AAC9E,kFAAkF;AAClF,4FAA4F;AAC5F,wFAAwF;AACxF,6FAA6F;AAC7F,sDAAsD;AACtD,8EAA8E;AAE9E,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAE5D,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACzE,OAAO,EAEL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,gBAAgB,MAAM,iBAAiB,CAAA;AAanD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACxE,mBAAmB,CAAC;QAClB,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,IAAI,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QACxE,aAAa,EAAE,IAAI,mBAAmB,CAAC,KAAK,CAAC;QAC7C,eAAe,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,qBAAqB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS;QACrF,YAAY,EAAE,IAAI,wBAAwB,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;KACvE,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { GitHubBranch, GitHubCheckRun, GitHubCommit, GitHubIssue, GitHubPullRequest, GitHubRepo } from '@cat-factory/kernel';
|
|
2
|
+
export interface GlProjectPayload {
|
|
3
|
+
id?: number;
|
|
4
|
+
path?: string;
|
|
5
|
+
path_with_namespace?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
default_branch?: string | null;
|
|
8
|
+
visibility?: string;
|
|
9
|
+
namespace?: {
|
|
10
|
+
path?: string;
|
|
11
|
+
full_path?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface GlBranchPayload {
|
|
15
|
+
name?: string;
|
|
16
|
+
protected?: boolean;
|
|
17
|
+
commit?: {
|
|
18
|
+
id?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface GlMergeRequestPayload {
|
|
22
|
+
id?: number;
|
|
23
|
+
iid?: number;
|
|
24
|
+
title?: string;
|
|
25
|
+
state?: string;
|
|
26
|
+
source_branch?: string | null;
|
|
27
|
+
target_branch?: string | null;
|
|
28
|
+
sha?: string | null;
|
|
29
|
+
author?: {
|
|
30
|
+
username?: string;
|
|
31
|
+
} | null;
|
|
32
|
+
updated_at?: string | null;
|
|
33
|
+
}
|
|
34
|
+
export interface GlIssuePayload {
|
|
35
|
+
id?: number;
|
|
36
|
+
iid?: number;
|
|
37
|
+
title?: string;
|
|
38
|
+
state?: string;
|
|
39
|
+
author?: {
|
|
40
|
+
username?: string;
|
|
41
|
+
} | null;
|
|
42
|
+
labels?: Array<string | {
|
|
43
|
+
name?: string;
|
|
44
|
+
}>;
|
|
45
|
+
updated_at?: string | null;
|
|
46
|
+
}
|
|
47
|
+
export interface GlCommitPayload {
|
|
48
|
+
id?: string;
|
|
49
|
+
message?: string;
|
|
50
|
+
author_name?: string | null;
|
|
51
|
+
authored_date?: string | null;
|
|
52
|
+
}
|
|
53
|
+
export interface GlCommitStatusPayload {
|
|
54
|
+
id?: number;
|
|
55
|
+
sha?: string;
|
|
56
|
+
name?: string;
|
|
57
|
+
status?: string;
|
|
58
|
+
target_url?: string | null;
|
|
59
|
+
}
|
|
60
|
+
/** Owner (namespace) + name for a GitLab project, used to fill the neutral ref. */
|
|
61
|
+
export declare function projectOwnerName(p: GlProjectPayload): {
|
|
62
|
+
owner: string;
|
|
63
|
+
name: string;
|
|
64
|
+
};
|
|
65
|
+
export declare function toRepoProjection(p: GlProjectPayload, connectionNumericId: number, syncedAt: number): GitHubRepo;
|
|
66
|
+
export declare function toBranchProjection(b: GlBranchPayload, repoId: number, syncedAt: number): GitHubBranch;
|
|
67
|
+
/** Map GitLab's MR `state` to the neutral open/closed + merged flag. */
|
|
68
|
+
export declare function mrState(state: string | undefined): {
|
|
69
|
+
state: 'open' | 'closed';
|
|
70
|
+
merged: boolean;
|
|
71
|
+
};
|
|
72
|
+
export declare function toMergeRequestProjection(mr: GlMergeRequestPayload, repoId: number, syncedAt: number): GitHubPullRequest;
|
|
73
|
+
export declare function toIssueProjection(i: GlIssuePayload, repoId: number, syncedAt: number): GitHubIssue;
|
|
74
|
+
export declare function toCommitProjection(c: GlCommitPayload, repoId: number, syncedAt: number): GitHubCommit;
|
|
75
|
+
/**
|
|
76
|
+
* Map a GitLab commit status / pipeline-job state to a GitHub-style check run so the
|
|
77
|
+
* shared CI gate (`aggregateCi`) reduces it correctly. GitHub semantics: terminal
|
|
78
|
+
* states are `status: 'completed'` with a `conclusion`; in-flight states are
|
|
79
|
+
* `status: 'in_progress'` with a null conclusion.
|
|
80
|
+
*/
|
|
81
|
+
export declare function toCheckRunProjection(s: GlCommitStatusPayload, repoId: number, syncedAt: number): GitHubCheckRun;
|
|
82
|
+
/** GitLab pipeline/commit-status state → GitHub check `status` + `conclusion`. */
|
|
83
|
+
export declare function checkState(state: string | undefined): {
|
|
84
|
+
status: string;
|
|
85
|
+
conclusion: string | null;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* GitLab mergeability → the neutral triplet the conflicts gate normalises. Prefers
|
|
89
|
+
* GitLab 15.6+ `detailed_merge_status` (precise) over the deprecated `merge_status`.
|
|
90
|
+
*
|
|
91
|
+
* Only a genuine textual `conflict` maps to GitHub's `dirty` state — the single signal
|
|
92
|
+
* the `conflicts` gate escalates a conflict-resolver on. Every OTHER non-mergeable reason
|
|
93
|
+
* (CI pending, unresolved discussions, behind target, draft, not open) is reported as
|
|
94
|
+
* not-mergeable-but-not-`dirty`, so `classifyMergeability` returns `mergeable` (nothing to
|
|
95
|
+
* resolve) and the gate advances instead of spuriously spawning a conflict-resolver.
|
|
96
|
+
* `checking`/`unchecked` stay `mergeable: null` so the gate re-polls.
|
|
97
|
+
*/
|
|
98
|
+
export declare function mergeabilityFromStatus(detailedStatus: string | undefined, legacyStatus?: string | undefined): {
|
|
99
|
+
mergeable: boolean | null;
|
|
100
|
+
mergeableState: string;
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/** Owner (namespace) + name for a GitLab project, used to fill the neutral ref. */
|
|
2
|
+
export function projectOwnerName(p) {
|
|
3
|
+
const name = p.path ?? p.name ?? '';
|
|
4
|
+
// `path_with_namespace` is `group/sub/project`; the owner is everything before the
|
|
5
|
+
// final segment. Fall back to the namespace path.
|
|
6
|
+
if (p.path_with_namespace && p.path_with_namespace.includes('/')) {
|
|
7
|
+
return { owner: p.path_with_namespace.slice(0, p.path_with_namespace.lastIndexOf('/')), name };
|
|
8
|
+
}
|
|
9
|
+
return { owner: p.namespace?.full_path ?? p.namespace?.path ?? '', name };
|
|
10
|
+
}
|
|
11
|
+
export function toRepoProjection(p, connectionNumericId, syncedAt) {
|
|
12
|
+
const { owner, name } = projectOwnerName(p);
|
|
13
|
+
return {
|
|
14
|
+
githubId: p.id ?? 0,
|
|
15
|
+
installationId: connectionNumericId,
|
|
16
|
+
owner,
|
|
17
|
+
name,
|
|
18
|
+
defaultBranch: p.default_branch ?? null,
|
|
19
|
+
private: p.visibility !== 'public',
|
|
20
|
+
blockId: null,
|
|
21
|
+
syncedAt,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function toBranchProjection(b, repoId, syncedAt) {
|
|
25
|
+
return {
|
|
26
|
+
repoGithubId: repoId,
|
|
27
|
+
name: b.name ?? '',
|
|
28
|
+
headSha: b.commit?.id ?? '',
|
|
29
|
+
protected: b.protected ?? false,
|
|
30
|
+
syncedAt,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Map GitLab's MR `state` to the neutral open/closed + merged flag. */
|
|
34
|
+
export function mrState(state) {
|
|
35
|
+
if (state === 'opened')
|
|
36
|
+
return { state: 'open', merged: false };
|
|
37
|
+
if (state === 'merged')
|
|
38
|
+
return { state: 'closed', merged: true };
|
|
39
|
+
// 'closed' | 'locked' | anything else
|
|
40
|
+
return { state: 'closed', merged: false };
|
|
41
|
+
}
|
|
42
|
+
export function toMergeRequestProjection(mr, repoId, syncedAt) {
|
|
43
|
+
const { state, merged } = mrState(mr.state);
|
|
44
|
+
return {
|
|
45
|
+
repoGithubId: repoId,
|
|
46
|
+
number: mr.iid ?? 0,
|
|
47
|
+
githubId: mr.id ?? 0,
|
|
48
|
+
title: mr.title ?? '',
|
|
49
|
+
state,
|
|
50
|
+
headRef: mr.source_branch ?? null,
|
|
51
|
+
baseRef: mr.target_branch ?? null,
|
|
52
|
+
headSha: mr.sha ?? null,
|
|
53
|
+
merged,
|
|
54
|
+
author: mr.author?.username ?? null,
|
|
55
|
+
updatedAt: parseTime(mr.updated_at),
|
|
56
|
+
syncedAt,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function toIssueProjection(i, repoId, syncedAt) {
|
|
60
|
+
return {
|
|
61
|
+
repoGithubId: repoId,
|
|
62
|
+
number: i.iid ?? 0,
|
|
63
|
+
githubId: i.id ?? 0,
|
|
64
|
+
title: i.title ?? '',
|
|
65
|
+
// GitLab issues are 'opened'/'closed'.
|
|
66
|
+
state: i.state === 'opened' ? 'open' : 'closed',
|
|
67
|
+
author: i.author?.username ?? null,
|
|
68
|
+
labels: (i.labels ?? [])
|
|
69
|
+
.map((l) => (typeof l === 'string' ? l : (l?.name ?? '')))
|
|
70
|
+
.filter(Boolean),
|
|
71
|
+
updatedAt: parseTime(i.updated_at),
|
|
72
|
+
syncedAt,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function toCommitProjection(c, repoId, syncedAt) {
|
|
76
|
+
return {
|
|
77
|
+
repoGithubId: repoId,
|
|
78
|
+
sha: c.id ?? '',
|
|
79
|
+
message: c.message ?? '',
|
|
80
|
+
author: c.author_name ?? null,
|
|
81
|
+
authoredAt: parseTime(c.authored_date),
|
|
82
|
+
syncedAt,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Map a GitLab commit status / pipeline-job state to a GitHub-style check run so the
|
|
87
|
+
* shared CI gate (`aggregateCi`) reduces it correctly. GitHub semantics: terminal
|
|
88
|
+
* states are `status: 'completed'` with a `conclusion`; in-flight states are
|
|
89
|
+
* `status: 'in_progress'` with a null conclusion.
|
|
90
|
+
*/
|
|
91
|
+
export function toCheckRunProjection(s, repoId, syncedAt) {
|
|
92
|
+
const { status, conclusion } = checkState(s.status);
|
|
93
|
+
return {
|
|
94
|
+
repoGithubId: repoId,
|
|
95
|
+
githubId: s.id ?? 0,
|
|
96
|
+
headSha: s.sha ?? '',
|
|
97
|
+
name: s.name ?? '',
|
|
98
|
+
status,
|
|
99
|
+
conclusion,
|
|
100
|
+
htmlUrl: s.target_url ?? null,
|
|
101
|
+
syncedAt,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** GitLab pipeline/commit-status state → GitHub check `status` + `conclusion`. */
|
|
105
|
+
export function checkState(state) {
|
|
106
|
+
switch (state) {
|
|
107
|
+
case 'success':
|
|
108
|
+
return { status: 'completed', conclusion: 'success' };
|
|
109
|
+
case 'failed':
|
|
110
|
+
return { status: 'completed', conclusion: 'failure' };
|
|
111
|
+
case 'canceled':
|
|
112
|
+
case 'cancelled':
|
|
113
|
+
return { status: 'completed', conclusion: 'cancelled' };
|
|
114
|
+
case 'skipped':
|
|
115
|
+
return { status: 'completed', conclusion: 'skipped' };
|
|
116
|
+
case 'manual':
|
|
117
|
+
// Awaiting a manual action — neutral (don't block the gate on an optional job).
|
|
118
|
+
return { status: 'completed', conclusion: 'neutral' };
|
|
119
|
+
default:
|
|
120
|
+
// created / waiting_for_resource / preparing / pending / running / scheduled
|
|
121
|
+
return { status: 'in_progress', conclusion: null };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* GitLab mergeability → the neutral triplet the conflicts gate normalises. Prefers
|
|
126
|
+
* GitLab 15.6+ `detailed_merge_status` (precise) over the deprecated `merge_status`.
|
|
127
|
+
*
|
|
128
|
+
* Only a genuine textual `conflict` maps to GitHub's `dirty` state — the single signal
|
|
129
|
+
* the `conflicts` gate escalates a conflict-resolver on. Every OTHER non-mergeable reason
|
|
130
|
+
* (CI pending, unresolved discussions, behind target, draft, not open) is reported as
|
|
131
|
+
* not-mergeable-but-not-`dirty`, so `classifyMergeability` returns `mergeable` (nothing to
|
|
132
|
+
* resolve) and the gate advances instead of spuriously spawning a conflict-resolver.
|
|
133
|
+
* `checking`/`unchecked` stay `mergeable: null` so the gate re-polls.
|
|
134
|
+
*/
|
|
135
|
+
export function mergeabilityFromStatus(detailedStatus, legacyStatus) {
|
|
136
|
+
if (detailedStatus) {
|
|
137
|
+
switch (detailedStatus) {
|
|
138
|
+
case 'mergeable':
|
|
139
|
+
return { mergeable: true, mergeableState: 'clean' };
|
|
140
|
+
case 'conflict':
|
|
141
|
+
return { mergeable: false, mergeableState: 'dirty' };
|
|
142
|
+
case 'checking':
|
|
143
|
+
case 'unchecked':
|
|
144
|
+
return { mergeable: null, mergeableState: detailedStatus };
|
|
145
|
+
default:
|
|
146
|
+
// not_open | draft_status | discussions_not_resolved | ci_must_pass |
|
|
147
|
+
// ci_still_running | need_rebase | broken_status | commits_status | …
|
|
148
|
+
return { mergeable: false, mergeableState: 'blocked' };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
switch (legacyStatus) {
|
|
152
|
+
case 'can_be_merged':
|
|
153
|
+
return { mergeable: true, mergeableState: 'clean' };
|
|
154
|
+
case 'cannot_be_merged':
|
|
155
|
+
// Ambiguous on the legacy field (a real conflict OR merely CI/discussions/draft).
|
|
156
|
+
// Report not-mergeable WITHOUT the `dirty` conflict signal so the gate does not
|
|
157
|
+
// escalate on a non-conflict block; `detailed_merge_status` (above) disambiguates.
|
|
158
|
+
return { mergeable: false, mergeableState: 'blocked' };
|
|
159
|
+
case 'checking':
|
|
160
|
+
case 'unchecked':
|
|
161
|
+
case 'cannot_be_merged_recheck':
|
|
162
|
+
return { mergeable: null, mergeableState: legacyStatus };
|
|
163
|
+
default:
|
|
164
|
+
return { mergeable: null, mergeableState: legacyStatus ?? 'unknown' };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function parseTime(value) {
|
|
168
|
+
if (!value)
|
|
169
|
+
return null;
|
|
170
|
+
const ms = Date.parse(value);
|
|
171
|
+
return Number.isFinite(ms) ? ms : null;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CreateRepoInput, InstallationPermissions, ProvisionedRepo, VcsConnectionRef, VcsProvisioningClient } from '@cat-factory/kernel';
|
|
2
|
+
import type { GitLabTokenSource } from './tokenSource.js';
|
|
3
|
+
export interface GitLabProvisioningDependencies {
|
|
4
|
+
tokenSource: GitLabTokenSource;
|
|
5
|
+
fetchImpl?: typeof fetch;
|
|
6
|
+
}
|
|
7
|
+
export declare class GitLabProvisioningClient implements VcsProvisioningClient {
|
|
8
|
+
private readonly deps;
|
|
9
|
+
constructor(deps: GitLabProvisioningDependencies);
|
|
10
|
+
getGrantedPermissions(connection: VcsConnectionRef): Promise<InstallationPermissions>;
|
|
11
|
+
createRepoInOrg(connection: VcsConnectionRef, input: CreateRepoInput): Promise<ProvisionedRepo>;
|
|
12
|
+
/** Resolve a group/namespace full-path to its numeric id, or null for a user namespace. */
|
|
13
|
+
private resolveNamespaceId;
|
|
14
|
+
private request;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=provisioning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../src/provisioning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AASzD,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,iBAAiB,CAAA;IAC9B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED,qBAAa,wBAAyB,YAAW,qBAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,8BAA8B,EAAI;IAE/D,qBAAqB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAO1F;IAEK,eAAe,CACnB,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,eAAe,CAAC,CAyB1B;IAED,2FAA2F;YAC7E,kBAAkB;YAgBlB,OAAO;CA6BtB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { GitLabApiError } from './FetchGitLabClient.js';
|
|
2
|
+
export class GitLabProvisioningClient {
|
|
3
|
+
deps;
|
|
4
|
+
constructor(deps) {
|
|
5
|
+
this.deps = deps;
|
|
6
|
+
}
|
|
7
|
+
async getGrantedPermissions(connection) {
|
|
8
|
+
// GitLab token scopes (e.g. `api`) aren't readable from a permission endpoint the way a
|
|
9
|
+
// GitHub installation token reports its granted set. A token that can hit the API can
|
|
10
|
+
// generally create projects in a namespace it owns; the actual create surfaces a 403
|
|
11
|
+
// otherwise. Report the optimistic grant so the provisioner attempts the create.
|
|
12
|
+
void connection;
|
|
13
|
+
return { administration: 'write', contents: 'write' };
|
|
14
|
+
}
|
|
15
|
+
async createRepoInOrg(connection, input) {
|
|
16
|
+
const namespaceId = await this.resolveNamespaceId(connection, input.org);
|
|
17
|
+
const body = {
|
|
18
|
+
name: input.name,
|
|
19
|
+
path: input.name,
|
|
20
|
+
visibility: input.private === false ? 'public' : 'private',
|
|
21
|
+
...(namespaceId !== null ? { namespace_id: namespaceId } : {}),
|
|
22
|
+
...(input.description ? { description: input.description } : {}),
|
|
23
|
+
...(input.autoInit ? { initialize_with_readme: true } : {}),
|
|
24
|
+
};
|
|
25
|
+
const json = await this.request(connection, '/projects', 'POST', body);
|
|
26
|
+
const p = (json ?? {});
|
|
27
|
+
return {
|
|
28
|
+
githubId: p.id ?? 0,
|
|
29
|
+
owner: input.org,
|
|
30
|
+
name: p.path ?? input.name,
|
|
31
|
+
defaultBranch: p.default_branch ?? null,
|
|
32
|
+
private: p.visibility !== 'public',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Resolve a group/namespace full-path to its numeric id, or null for a user namespace. */
|
|
36
|
+
async resolveNamespaceId(connection, org) {
|
|
37
|
+
try {
|
|
38
|
+
const json = await this.request(connection, `/namespaces/${encodeURIComponent(org)}`, 'GET');
|
|
39
|
+
const id = json.id;
|
|
40
|
+
return typeof id === 'number' ? id : null;
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
// No matching namespace (or no access) → let the create default to the token user's
|
|
44
|
+
// own namespace rather than failing the resolution step.
|
|
45
|
+
if (err instanceof GitLabApiError && err.status === 404)
|
|
46
|
+
return null;
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async request(connection, path, method, body) {
|
|
51
|
+
const apiBase = this.deps.tokenSource.apiBase(connection);
|
|
52
|
+
const token = await this.deps.tokenSource.token(connection);
|
|
53
|
+
const headers = {
|
|
54
|
+
'private-token': token,
|
|
55
|
+
accept: 'application/json',
|
|
56
|
+
'user-agent': 'cat-factory',
|
|
57
|
+
};
|
|
58
|
+
if (body !== undefined)
|
|
59
|
+
headers['content-type'] = 'application/json';
|
|
60
|
+
const fetchImpl = this.deps.fetchImpl ?? fetch;
|
|
61
|
+
const res = await fetchImpl(`${apiBase}${path}`, {
|
|
62
|
+
method,
|
|
63
|
+
headers,
|
|
64
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
const text = await res.text().catch(() => '');
|
|
68
|
+
throw new GitLabApiError(res.status, `GitLab ${method} ${path} → ${res.status}: ${text.slice(0, 300)}`);
|
|
69
|
+
}
|
|
70
|
+
return res.status === 204 ? null : await res.json().catch(() => null);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=provisioning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.js","sourceRoot":"","sources":["../src/provisioning.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { VcsConnectionRef } from '@cat-factory/kernel';
|
|
2
|
+
export interface GitLabTokenSource {
|
|
3
|
+
/** The access token to send for calls on this connection (`PRIVATE-TOKEN` header). */
|
|
4
|
+
token(connection: VcsConnectionRef): Promise<string>;
|
|
5
|
+
/**
|
|
6
|
+
* The REST API base for this connection, e.g. `https://gitlab.com/api/v4` for
|
|
7
|
+
* gitlab.com or `https://gitlab.example.com/api/v4` for a self-managed instance.
|
|
8
|
+
* Per-connection so different connections can target different instances.
|
|
9
|
+
*/
|
|
10
|
+
apiBase(connection: VcsConnectionRef): string;
|
|
11
|
+
}
|
|
12
|
+
/** The public gitlab.com REST v4 base. */
|
|
13
|
+
export declare const GITLAB_PUBLIC_API_BASE = "https://gitlab.com/api/v4";
|
|
14
|
+
/**
|
|
15
|
+
* A fixed-token source: every connection uses the same token + base URL. Useful for a
|
|
16
|
+
* single-token deployment (mirrors local mode's PAT model) and for tests.
|
|
17
|
+
*/
|
|
18
|
+
export declare class StaticGitLabTokenSource implements GitLabTokenSource {
|
|
19
|
+
private readonly accessToken;
|
|
20
|
+
private readonly base;
|
|
21
|
+
constructor(accessToken: string, base?: string);
|
|
22
|
+
token(): Promise<string>;
|
|
23
|
+
apiBase(): string;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=tokenSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenSource.d.ts","sourceRoot":"","sources":["../src/tokenSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAU3D,MAAM,WAAW,iBAAiB;IAChC,sFAAsF;IACtF,KAAK,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACpD;;;;OAIG;IACH,OAAO,CAAC,UAAU,EAAE,gBAAgB,GAAG,MAAM,CAAA;CAC9C;AAED,0CAA0C;AAC1C,eAAO,MAAM,sBAAsB,8BAA8B,CAAA;AAEjE;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,iBAAiB;IAE7D,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFvB,YACmB,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,MAA+B,EACpD;IAEE,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAE7B;IAED,OAAO,IAAI,MAAM,CAEhB;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** The public gitlab.com REST v4 base. */
|
|
2
|
+
export const GITLAB_PUBLIC_API_BASE = 'https://gitlab.com/api/v4';
|
|
3
|
+
/**
|
|
4
|
+
* A fixed-token source: every connection uses the same token + base URL. Useful for a
|
|
5
|
+
* single-token deployment (mirrors local mode's PAT model) and for tests.
|
|
6
|
+
*/
|
|
7
|
+
export class StaticGitLabTokenSource {
|
|
8
|
+
accessToken;
|
|
9
|
+
base;
|
|
10
|
+
constructor(accessToken, base = GITLAB_PUBLIC_API_BASE) {
|
|
11
|
+
this.accessToken = accessToken;
|
|
12
|
+
this.base = base;
|
|
13
|
+
}
|
|
14
|
+
async token() {
|
|
15
|
+
return this.accessToken;
|
|
16
|
+
}
|
|
17
|
+
apiBase() {
|
|
18
|
+
return this.base;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=tokenSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenSource.js","sourceRoot":"","sources":["../src/tokenSource.ts"],"names":[],"mappings":"AAqBA,0CAA0C;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,2BAA2B,CAAA;AAEjE;;;GAGG;AACH,MAAM,OAAO,uBAAuB;IAEf,WAAW;IACX,IAAI;IAFvB,YACmB,WAAmB,EACnB,IAAI,GAAW,sBAAsB;2BADrC,WAAW;oBACX,IAAI;IACpB,CAAC;IAEJ,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Clock, RawWebhookDelivery, VcsConnectionRef, VcsWebhookEvent, VcsWebhookMapper, WebhookVerifier } from '@cat-factory/kernel';
|
|
2
|
+
/**
|
|
3
|
+
* Verifies the `X-Gitlab-Token` header against the configured secret in constant time.
|
|
4
|
+
* The `WebhookVerifier` port's `verify(rawBody, signatureHeader)` is reused: GitLab passes
|
|
5
|
+
* the token header as `signatureHeader` (the body is irrelevant to GitLab verification).
|
|
6
|
+
*/
|
|
7
|
+
export declare class GitLabWebhookVerifier implements WebhookVerifier {
|
|
8
|
+
private readonly secret;
|
|
9
|
+
constructor(secret: string);
|
|
10
|
+
verify(_rawBody: ArrayBuffer, signatureHeader: string | null): Promise<boolean>;
|
|
11
|
+
}
|
|
12
|
+
export declare class GitLabWebhookMapper implements VcsWebhookMapper {
|
|
13
|
+
private readonly clock;
|
|
14
|
+
constructor(clock: Clock);
|
|
15
|
+
map(connection: VcsConnectionRef, delivery: RawWebhookDelivery): VcsWebhookEvent | null;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,kBAAkB,EAClB,gBAAgB,EAEhB,eAAe,EACf,gBAAgB,EAChB,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAY5B;;;;GAIG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAAnC,YAA6B,MAAM,EAAE,MAAM,EAAI;IAEzC,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAGpF;CACF;AA2BD,qBAAa,mBAAoB,YAAW,gBAAgB;IAG9C,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAlC,YAA6B,KAAK,EAAE,KAAK,EAAI;IAE7C,GAAG,CAAC,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,kBAAkB,GAAG,eAAe,GAAG,IAAI,CA8GtF;CACF"}
|