@simplysf/simply-gitlab-core 0.1.0 → 0.3.0

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.
@@ -0,0 +1,412 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { entryKey, entryLabel, normalizeSection, } from './baseline-config.js';
17
+ import { AuthError, HttpError } from './errors.js';
18
+ /** Whether a plan would change anything if applied. */
19
+ export function hasChanges(plan) {
20
+ return plan.targets.some((target) => target.error !== undefined || target.sections.some((s) => s.actions.length > 0));
21
+ }
22
+ /** Every drift a plan found, including the parts it would not correct. */
23
+ export function hasDrift(plan) {
24
+ return plan.targets.some((target) => target.error !== undefined || target.sections.some((s) => s.changes.length > 0));
25
+ }
26
+ /**
27
+ * `PATCH` on a protected branch cannot change fields the config does not resend, and neither the
28
+ * approval-rule nor the branch APIs echo their inputs in the same shape they accept them. So
29
+ * comparison is by JSON value on the fields the config declares, and nothing else is looked at.
30
+ */
31
+ function sameValue(left, right) {
32
+ return JSON.stringify(normalize(left)) === JSON.stringify(normalize(right));
33
+ }
34
+ /** Sorts object keys so two equivalent objects compare equal regardless of key order. */
35
+ function normalize(value) {
36
+ if (Array.isArray(value))
37
+ return value.map(normalize);
38
+ if (typeof value === 'object' && value !== null) {
39
+ return Object.fromEntries(Object.entries(value)
40
+ .filter(([, v]) => v !== undefined)
41
+ .sort(([a], [b]) => a.localeCompare(b))
42
+ .map(([k, v]) => [k, normalize(v)]));
43
+ }
44
+ return value;
45
+ }
46
+ /**
47
+ * Diffs the attributes a config declares against what the instance reports, ignoring everything
48
+ * else. This is the whole reason a baseline is safe to run against projects that already exist:
49
+ * the blast radius is the set of keys someone wrote down.
50
+ */
51
+ function diffAttributes(desired, actual) {
52
+ const changes = [];
53
+ const body = {};
54
+ for (const [key, want] of Object.entries(desired)) {
55
+ const have = actual[key];
56
+ if (!sameValue(want, have)) {
57
+ changes.push({ op: 'update', key, from: have, to: want });
58
+ body[key] = want;
59
+ }
60
+ }
61
+ return { changes, body };
62
+ }
63
+ function asRecord(value) {
64
+ return (typeof value === 'object' && value !== null ? value : {});
65
+ }
66
+ function supported(section, changes, actions) {
67
+ return { section, supported: true, changes, actions };
68
+ }
69
+ function unsupported(section, reason) {
70
+ return { section, supported: false, unsupportedReason: reason, changes: [], actions: [] };
71
+ }
72
+ /**
73
+ * Runs a read that may not be available on this instance.
74
+ *
75
+ * Approval rules, approval settings, and push rules are Premium/Ultimate. A 403 or 404 there means
76
+ * the section does not exist rather than that the run failed, so the other sections still converge
77
+ * and the plan says which one was skipped and why.
78
+ */
79
+ async function readOptional(read) {
80
+ try {
81
+ return { ok: true, value: await read() };
82
+ }
83
+ catch (error) {
84
+ if (error instanceof AuthError && error.status === 403) {
85
+ return { ok: false, reason: 'not available to this token, or not on this plan (403)' };
86
+ }
87
+ if (error instanceof HttpError && error.status === 404) {
88
+ return { ok: false, reason: 'not available on this instance (404)' };
89
+ }
90
+ throw error;
91
+ }
92
+ }
93
+ // --- Section planners ---------------------------------------------------------------------------
94
+ async function planSettings(client, ref, desired) {
95
+ if (desired.settings === undefined)
96
+ return [];
97
+ const actual = asRecord(await client.getProject(ref));
98
+ const { changes, body } = diffAttributes(desired.settings, actual);
99
+ return [supported('settings', changes, changes.length === 0 ? [] : [{ kind: 'updateProject', body }])];
100
+ }
101
+ /**
102
+ * Protected branches, which are the one section where the update mechanism materially changes what
103
+ * a plan means. `PATCH` corrects a protection in place; a rename cannot be patched, so it reads as
104
+ * a delete and a create — and that pair leaves the branch unprotected in between, which the plan
105
+ * labels rather than leaving anyone to discover.
106
+ */
107
+ async function planProtectedBranches(client, ref, desired) {
108
+ const section = normalizeSection(desired.protectedBranches);
109
+ if (section === undefined)
110
+ return [];
111
+ const actual = (await client.listProtectedBranches(ref)).items.map(asRecord);
112
+ return [
113
+ planKeyedSection('protectedBranches', section, actual, {
114
+ create: (entry) => ({ kind: 'protectBranch', body: { ...entry } }),
115
+ update: (entry, body) => ({ kind: 'patchProtectedBranch', name: String(entry.name), body }),
116
+ remove: (entry) => ({ kind: 'unprotectBranch', name: String(entry.name) }),
117
+ }),
118
+ ];
119
+ }
120
+ /** Protected tags have no update endpoint, so a change is a delete and a create, and says so. */
121
+ async function planProtectedTags(client, ref, desired) {
122
+ const section = normalizeSection(desired.protectedTags);
123
+ if (section === undefined)
124
+ return [];
125
+ const actual = (await client.listProtectedTags(ref)).items.map(asRecord);
126
+ return [
127
+ planKeyedSection('protectedTags', section, actual, {
128
+ create: (entry) => ({ kind: 'protectTag', body: { ...entry } }),
129
+ update: (entry) => ({ kind: 'protectTag', body: { ...entry } }),
130
+ remove: (entry) => ({ kind: 'unprotectTag', name: String(entry.name) }),
131
+ recreate: 'protected tags have no update endpoint, so this is a delete and a create',
132
+ beforeUpdate: (entry) => ({ kind: 'unprotectTag', name: String(entry.name) }),
133
+ }),
134
+ ];
135
+ }
136
+ async function planApprovals(client, ref, desired) {
137
+ if (desired.approvals === undefined)
138
+ return [];
139
+ const read = await readOptional(() => client.getApprovalSettings(ref));
140
+ if (!read.ok)
141
+ return [unsupported('approvals', read.reason)];
142
+ const { changes, body } = diffAttributes(desired.approvals, asRecord(read.value));
143
+ return [supported('approvals', changes, changes.length === 0 ? [] : [{ kind: 'updateApprovalSettings', body }])];
144
+ }
145
+ /**
146
+ * Approval rules, where the config speaks in names and the API speaks in ids.
147
+ *
148
+ * `usernames` the API takes directly. Group paths and protected-branch names it does not, so those
149
+ * are carried on the action and resolved at apply time — the branch ids in particular cannot be
150
+ * resolved now, because the branch may be created by the section that runs immediately before this
151
+ * one.
152
+ */
153
+ async function planApprovalRules(client, ref, desired) {
154
+ const section = normalizeSection(desired.approvalRules);
155
+ if (section === undefined)
156
+ return [];
157
+ const read = await readOptional(() => client.listApprovalRules(ref));
158
+ if (!read.ok)
159
+ return [unsupported('approvalRules', read.reason)];
160
+ const actual = read.value.items.map(asRecord);
161
+ const byName = new Map(actual.map((rule) => [String(rule.name), rule]));
162
+ const changes = [];
163
+ const actions = [];
164
+ for (const entry of section.entries) {
165
+ const name = String(entry.name);
166
+ const branches = Array.isArray(entry.protectedBranches) ? entry.protectedBranches : undefined;
167
+ const body = ruleBody(entry);
168
+ const existing = byName.get(name);
169
+ if (existing === undefined) {
170
+ changes.push({ op: 'create', key: name, to: summarise(entry) });
171
+ actions.push({ kind: 'createApprovalRule', body, branches });
172
+ continue;
173
+ }
174
+ const attributeChanges = compareRule(entry, existing);
175
+ if (attributeChanges.length > 0) {
176
+ changes.push(...attributeChanges.map((change) => ({ ...change, key: `${name}.${change.key}` })));
177
+ actions.push({ kind: 'updateApprovalRule', ruleId: Number(existing.id), body, branches });
178
+ }
179
+ }
180
+ const declared = new Set(section.entries.map((entry) => String(entry.name)));
181
+ for (const rule of actual) {
182
+ const name = String(rule.name);
183
+ // `any_approver` is GitLab's implicit fallback rule, not something a config declared or should
184
+ // delete; pruning it would remove the project's default approval behaviour.
185
+ if (declared.has(name) || rule.rule_type === 'any_approver')
186
+ continue;
187
+ changes.push({
188
+ op: 'delete',
189
+ key: name,
190
+ detail: section.prune ? undefined : 'not pruned; set "prune": true on this section to remove it',
191
+ });
192
+ if (section.prune)
193
+ actions.push({ kind: 'deleteApprovalRule', ruleId: Number(rule.id) });
194
+ }
195
+ return [supported('approvalRules', changes, actions)];
196
+ }
197
+ /** The rule attributes the API accepts, with the config's name-based references left off. */
198
+ function ruleBody(entry) {
199
+ const body = {};
200
+ for (const [key, value] of Object.entries(entry)) {
201
+ if (key === 'protectedBranches' || key === 'groups')
202
+ continue;
203
+ body[key] = value;
204
+ }
205
+ return body;
206
+ }
207
+ /** Compares only what the config declared, translating its name-based fields onto the payload. */
208
+ function compareRule(entry, actual) {
209
+ const changes = [];
210
+ for (const [key, want] of Object.entries(entry)) {
211
+ if (key === 'name')
212
+ continue;
213
+ if (key === 'usernames') {
214
+ const have = (Array.isArray(actual.eligible_approvers) ? actual.eligible_approvers : [])
215
+ .map((user) => asRecord(user).username)
216
+ .filter((username) => typeof username === 'string');
217
+ if (!sameValue([...want].sort(), [...have].sort())) {
218
+ changes.push({ op: 'update', key, from: have, to: want });
219
+ }
220
+ continue;
221
+ }
222
+ if (key === 'groups') {
223
+ const have = (Array.isArray(actual.groups) ? actual.groups : [])
224
+ .map((group) => asRecord(group).full_path)
225
+ .filter((path) => typeof path === 'string');
226
+ if (!sameValue([...want].sort(), [...have].sort())) {
227
+ changes.push({ op: 'update', key, from: have, to: want });
228
+ }
229
+ continue;
230
+ }
231
+ if (key === 'protectedBranches') {
232
+ const have = (Array.isArray(actual.protected_branches) ? actual.protected_branches : [])
233
+ .map((branch) => asRecord(branch).name)
234
+ .filter((name) => typeof name === 'string');
235
+ if (!sameValue([...want].sort(), [...have].sort())) {
236
+ changes.push({ op: 'update', key, from: have, to: want });
237
+ }
238
+ continue;
239
+ }
240
+ if (!sameValue(want, actual[key]))
241
+ changes.push({ op: 'update', key, from: actual[key], to: want });
242
+ }
243
+ return changes;
244
+ }
245
+ async function planPushRules(client, ref, desired) {
246
+ if (desired.pushRules === undefined)
247
+ return [];
248
+ const read = await readOptional(() => client.getPushRules(ref));
249
+ if (!read.ok)
250
+ return [unsupported('pushRules', read.reason)];
251
+ // A project with no push rules answers 200 with null rather than 404.
252
+ const existing = read.value !== null && read.value !== undefined;
253
+ const { changes, body } = diffAttributes(desired.pushRules, asRecord(read.value));
254
+ return [
255
+ supported('pushRules', changes, changes.length === 0 ? [] : [{ kind: 'setPushRules', body, exists: existing }]),
256
+ ];
257
+ }
258
+ /**
259
+ * Variables are reported, never written.
260
+ *
261
+ * Both POST and PUT require a `value`, and a `masked_and_hidden` variable's value is not even
262
+ * readable, so there is no honest way to reconcile them from a config that by design holds no
263
+ * values. Naming which projects are missing a key is still the question people actually ask.
264
+ */
265
+ async function planVariables(client, ref, desired) {
266
+ const section = normalizeSection(desired.variables);
267
+ if (section === undefined)
268
+ return [];
269
+ const read = await readOptional(() => client.listVariables(ref, 200));
270
+ if (!read.ok)
271
+ return [unsupported('variables', read.reason)];
272
+ const actual = read.value.items.map(asRecord);
273
+ const byKey = new Map(actual.map((variable) => [entryKey('variables', variable), variable]));
274
+ const changes = [];
275
+ for (const entry of section.entries) {
276
+ const existing = byKey.get(entryKey('variables', entry));
277
+ const label = entryLabel('variables', entry);
278
+ if (existing === undefined) {
279
+ changes.push({ op: 'report', key: label, detail: 'missing; create it with a value by hand' });
280
+ continue;
281
+ }
282
+ for (const [attribute, want] of Object.entries(entry)) {
283
+ if (attribute === 'key' || attribute === 'environment_scope')
284
+ continue;
285
+ if (!sameValue(want, existing[attribute])) {
286
+ changes.push({
287
+ op: 'report',
288
+ key: `${label}.${attribute}`,
289
+ from: existing[attribute],
290
+ to: want,
291
+ detail: 'cannot be corrected without resending the value',
292
+ });
293
+ }
294
+ }
295
+ }
296
+ // Deliberately no `actions`: this section never writes, whatever `prune` says.
297
+ return [supported('variables', changes, [])];
298
+ }
299
+ /** A short description of an entry, for a create line in the plan. */
300
+ function summarise(entry) {
301
+ return Object.entries(entry)
302
+ .filter(([key]) => key !== 'name')
303
+ .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(', ') : String(value)}`)
304
+ .join(', ');
305
+ }
306
+ /** The shared shape of every keyed list section: create what is missing, correct what differs. */
307
+ function planKeyedSection(section, desired, actual, handlers) {
308
+ const byKey = new Map(actual.map((item) => [entryKey(section, item), item]));
309
+ const changes = [];
310
+ const actions = [];
311
+ for (const entry of desired.entries) {
312
+ const key = entryKey(section, entry);
313
+ const label = entryLabel(section, entry);
314
+ const existing = byKey.get(key);
315
+ if (existing === undefined) {
316
+ changes.push({ op: 'create', key: label, to: summarise(entry) });
317
+ actions.push(handlers.create(entry));
318
+ continue;
319
+ }
320
+ const declared = Object.fromEntries(Object.entries(entry).filter(([field]) => field !== 'name'));
321
+ const { changes: attributeChanges, body } = diffAttributes(declared, existing);
322
+ if (attributeChanges.length === 0)
323
+ continue;
324
+ if (handlers.recreate !== undefined) {
325
+ changes.push(...attributeChanges.map((change) => ({ ...change, key: `${label}.${change.key}`, detail: handlers.recreate })));
326
+ if (handlers.beforeUpdate)
327
+ actions.push(handlers.beforeUpdate(entry));
328
+ actions.push(handlers.update(entry, body));
329
+ }
330
+ else {
331
+ changes.push(...attributeChanges.map((change) => ({ ...change, key: `${label}.${change.key}` })));
332
+ actions.push(handlers.update(entry, body));
333
+ }
334
+ }
335
+ const declaredKeys = new Set(desired.entries.map((entry) => entryKey(section, entry)));
336
+ for (const item of actual) {
337
+ const key = entryKey(section, item);
338
+ if (declaredKeys.has(key))
339
+ continue;
340
+ changes.push({
341
+ op: 'delete',
342
+ key: entryLabel(section, item),
343
+ detail: desired.prune ? undefined : 'not pruned; set "prune": true on this section to remove it',
344
+ });
345
+ if (desired.prune)
346
+ actions.push(handlers.remove(item));
347
+ }
348
+ return supported(section, changes, actions);
349
+ }
350
+ // --- Target planners ----------------------------------------------------------------------------
351
+ /**
352
+ * The order sections are planned and applied in. Settings first because some of them gate what the
353
+ * later ones can set; approval rules after protected branches because a rule scoped to a branch
354
+ * needs that branch to exist before it can reference it.
355
+ */
356
+ const PROJECT_PLANNERS = [
357
+ planSettings,
358
+ planProtectedBranches,
359
+ planProtectedTags,
360
+ planApprovals,
361
+ planApprovalRules,
362
+ planPushRules,
363
+ planVariables,
364
+ ];
365
+ /** Plans one project. Never throws for an instance failure; the target carries the error instead. */
366
+ export async function planProject(client, target, desired) {
367
+ const sections = [];
368
+ try {
369
+ /* Sections are read in a fixed order rather than concurrently: the order is part of the
370
+ contract, and a project's own reads are not the bottleneck across fifty of them. */
371
+ /* eslint-disable no-await-in-loop */
372
+ for (const planner of PROJECT_PLANNERS) {
373
+ sections.push(...(await planner(client, target.path, desired)));
374
+ }
375
+ /* eslint-enable no-await-in-loop */
376
+ }
377
+ catch (error) {
378
+ return {
379
+ kind: 'project',
380
+ path: target.path,
381
+ id: target.id,
382
+ sections,
383
+ error: error instanceof Error ? error.message : String(error),
384
+ };
385
+ }
386
+ return { kind: 'project', path: target.path, id: target.id, sections };
387
+ }
388
+ export async function planGroup(client, target, desired) {
389
+ if (desired.settings === undefined) {
390
+ return { kind: 'group', path: target.path, id: target.id, sections: [] };
391
+ }
392
+ try {
393
+ const actual = asRecord(await client.getGroup(target.path));
394
+ const { changes, body } = diffAttributes(desired.settings, actual);
395
+ return {
396
+ kind: 'group',
397
+ path: target.path,
398
+ id: target.id,
399
+ sections: [supported('settings', changes, changes.length === 0 ? [] : [{ kind: 'updateGroup', body }])],
400
+ };
401
+ }
402
+ catch (error) {
403
+ return {
404
+ kind: 'group',
405
+ path: target.path,
406
+ id: target.id,
407
+ sections: [],
408
+ error: error instanceof Error ? error.message : String(error),
409
+ };
410
+ }
411
+ }
412
+ //# sourceMappingURL=baseline-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-plan.js","sourceRoot":"","sources":["../src/baseline-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ApplyResult } from './baseline-apply.js';
2
+ import type { BaselinePlan } from './baseline-plan.js';
3
+ /** The whole plan, target by target, with a closing summary. */
4
+ export declare function renderPlan(plan: BaselinePlan): string;
5
+ /**
6
+ * The plan as data, for `--json` and for the MCP tool.
7
+ *
8
+ * `actions` are deliberately dropped: they are how apply executes, not something a caller should
9
+ * depend on, and publishing them would make an internal shape part of the contract.
10
+ */
11
+ export declare function planToJson(plan: BaselinePlan): unknown;
12
+ /** What an apply actually did, after the fact. */
13
+ export declare function renderApply(result: ApplyResult): string;
@@ -0,0 +1,139 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { summarise } from './baseline-run.js';
17
+ import { stripControlOneLine } from './text.js';
18
+ /**
19
+ * Renders a plan for a person to read before deciding to apply it.
20
+ *
21
+ * Lives in core rather than in the command for the same reason the table column sets do: the MCP
22
+ * server publishes this plan too, and a renderer only the CLI knew about would drift from what the
23
+ * tool describes. Nothing here writes to a stream; it returns a string.
24
+ */
25
+ /** Values in a plan are whatever GitLab returned, so they are rendered defensively. */
26
+ function value(input) {
27
+ if (input === undefined)
28
+ return 'unset';
29
+ if (input === null)
30
+ return 'null';
31
+ if (typeof input === 'string')
32
+ return stripControlOneLine(input) || "''";
33
+ if (Array.isArray(input))
34
+ return input.length === 0 ? '[]' : `[${input.map((item) => value(item)).join(', ')}]`;
35
+ if (typeof input === 'object')
36
+ return stripControlOneLine(JSON.stringify(input));
37
+ if (typeof input === 'number' || typeof input === 'boolean')
38
+ return String(input);
39
+ // Anything else came from server JSON; serialise rather than coerce it to [object Object].
40
+ return stripControlOneLine(JSON.stringify(input) ?? '');
41
+ }
42
+ const MARKS = {
43
+ create: '+',
44
+ update: '~',
45
+ delete: '-',
46
+ recreate: '±',
47
+ report: '!',
48
+ };
49
+ function renderChange(change) {
50
+ const mark = MARKS[change.op];
51
+ const key = stripControlOneLine(change.key);
52
+ if (change.op === 'update') {
53
+ const detail = change.detail === undefined ? '' : ` (${change.detail})`;
54
+ return ` ${mark} ${key} ${value(change.from)} → ${value(change.to)}${detail}`;
55
+ }
56
+ if (change.op === 'report') {
57
+ const shift = change.to === undefined ? '' : ` ${value(change.from)} → ${value(change.to)}`;
58
+ return ` ${mark} ${key}${shift} (${change.detail ?? 'reported only'})`;
59
+ }
60
+ const detail = change.detail === undefined ? '' : ` (${change.detail})`;
61
+ const extra = change.to === undefined ? '' : ` ${value(change.to)}`;
62
+ return ` ${mark} ${key}${extra}${detail}`;
63
+ }
64
+ function renderSection(section) {
65
+ if (!section.supported) {
66
+ return [` ${section.section}`, ` ! ${section.unsupportedReason ?? 'unsupported on this instance'}`];
67
+ }
68
+ if (section.changes.length === 0)
69
+ return [];
70
+ return [` ${section.section}`, ...section.changes.map(renderChange)];
71
+ }
72
+ function renderTarget(target) {
73
+ const heading = target.kind === 'group' ? `${target.path} (group)` : target.path;
74
+ if (target.error !== undefined) {
75
+ return [heading, ` ✗ ${stripControlOneLine(target.error)}`];
76
+ }
77
+ const body = target.sections.flatMap(renderSection);
78
+ if (body.length === 0)
79
+ return [heading, ' ✓ matches the baseline'];
80
+ return [heading, ...body];
81
+ }
82
+ /** The whole plan, target by target, with a closing summary. */
83
+ export function renderPlan(plan) {
84
+ const blocks = plan.targets.map((target) => renderTarget(target).join('\n'));
85
+ const counts = summarise(plan);
86
+ const parts = [
87
+ `${counts.targets} target(s): ${counts.matching} match, ${counts.differing} differ`,
88
+ counts.failed > 0 ? `${counts.failed} failed` : undefined,
89
+ counts.unsupported > 0 ? `${counts.unsupported} with an unsupported section` : undefined,
90
+ ].filter((part) => part !== undefined);
91
+ return [blocks.join('\n\n'), `${parts.join(', ')}.`].join('\n\n');
92
+ }
93
+ /**
94
+ * The plan as data, for `--json` and for the MCP tool.
95
+ *
96
+ * `actions` are deliberately dropped: they are how apply executes, not something a caller should
97
+ * depend on, and publishing them would make an internal shape part of the contract.
98
+ */
99
+ export function planToJson(plan) {
100
+ return {
101
+ targets: plan.targets.map((target) => ({
102
+ kind: target.kind,
103
+ path: target.path,
104
+ id: target.id,
105
+ ...(target.error === undefined ? {} : { error: target.error }),
106
+ sections: target.sections.map((section) => ({
107
+ section: section.section,
108
+ supported: section.supported,
109
+ ...(section.unsupportedReason === undefined ? {} : { unsupportedReason: section.unsupportedReason }),
110
+ changes: section.changes,
111
+ willChange: section.actions.length > 0,
112
+ })),
113
+ })),
114
+ summary: summarise(plan),
115
+ };
116
+ }
117
+ /** What an apply actually did, after the fact. */
118
+ export function renderApply(result) {
119
+ const lines = [];
120
+ let applied = 0;
121
+ let failed = 0;
122
+ for (const target of result.targets) {
123
+ applied += target.applied;
124
+ if (target.error !== undefined) {
125
+ failed += 1;
126
+ const where = target.failedSection === undefined ? '' : ` in ${target.failedSection}`;
127
+ lines.push(`${target.path}`);
128
+ lines.push(` ✗ stopped${where} after ${target.applied} change(s): ${stripControlOneLine(target.error)}`);
129
+ continue;
130
+ }
131
+ if (target.applied > 0)
132
+ lines.push(`${target.path} ✓ ${target.applied} change(s)`);
133
+ }
134
+ const summary = failed === 0
135
+ ? `Applied ${applied} change(s) across ${result.targets.length} target(s).`
136
+ : `Applied ${applied} change(s); ${failed} target(s) failed. Run plan again to see what is left.`;
137
+ return lines.length === 0 ? summary : [lines.join('\n'), summary].join('\n\n');
138
+ }
139
+ //# sourceMappingURL=baseline-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-render.js","sourceRoot":"","sources":["../src/baseline-render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { type BaselineConfig } from './baseline-config.js';
2
+ import { type BaselinePlan, type TargetPlan } from './baseline-plan.js';
3
+ import { type ResolvedTargets } from './baseline-targets.js';
4
+ import type { GitLabClient } from './gitlab-client.js';
5
+ /** How a run is paced and how it reacts to a target failing. */
6
+ export interface RunOptions {
7
+ /**
8
+ * How many targets are in flight at once. Small on purpose: the transport already retries 429
9
+ * with a capped Retry-After, so setting this high trades a shared instance's responsiveness for
10
+ * very little wall-clock.
11
+ */
12
+ readonly concurrency?: number;
13
+ /** Stop at the first target that fails, for when a systematic problem makes the rest pointless. */
14
+ readonly failFast?: boolean;
15
+ /** Narrow the run to these project paths without editing the config. */
16
+ readonly only?: readonly string[];
17
+ }
18
+ export declare const DEFAULT_CONCURRENCY = 4;
19
+ export interface PlannedRun {
20
+ readonly targets: ResolvedTargets;
21
+ readonly plan: BaselinePlan;
22
+ }
23
+ /**
24
+ * Runs `worker` over `items` with at most `limit` in flight, preserving input order in the result.
25
+ *
26
+ * A pool rather than `Promise.all` in chunks: with fifty targets of uneven size, chunking waits for
27
+ * the slowest project in each batch before starting the next, which is most of the run.
28
+ */
29
+ export declare function mapPool<T, R>(items: readonly T[], limit: number, worker: (item: T, index: number) => Promise<R>,
30
+ /** Return true to stop scheduling further items. Those already in flight still finish. */
31
+ stopAfter?: (result: R) => boolean): Promise<R[]>;
32
+ /**
33
+ * Resolves the targets and plans every one of them.
34
+ *
35
+ * Groups are planned before projects, matching the order `apply` writes them in: a group setting
36
+ * that projects inherit should be in place before the projects are looked at.
37
+ */
38
+ export declare function planRun(client: GitLabClient, config: BaselineConfig, options?: RunOptions): Promise<PlannedRun>;
39
+ /** What a plan or an apply amounted to, for the closing summary and the exit code. */
40
+ export interface RunSummary {
41
+ readonly targets: number;
42
+ readonly matching: number;
43
+ readonly differing: number;
44
+ readonly failed: number;
45
+ readonly unsupported: number;
46
+ }
47
+ export declare function summarise(plan: BaselinePlan): RunSummary;
48
+ /** Targets that could not be planned or applied, for reporting before the exit code. */
49
+ export declare function failures(plan: BaselinePlan): readonly TargetPlan[];