@simplysf/simply-gitlab 0.2.0 → 0.4.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,69 @@
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 { Flags } from '@oclif/core';
17
+ import { CliError, hasDrift, loadBaselineConfig, planRun, planToJson, renderPlan } from '@simplysf/simply-gitlab-core';
18
+ import { GitLabCommand } from '../../../shared/base-command.js';
19
+ import { baselineFlags } from '../../../shared/baseline-flags.js';
20
+ export default class GitlabConfigPlan extends GitLabCommand {
21
+ static summary = 'Report how projects differ from a baseline config.';
22
+ static description = 'Reads the baseline, expands its targets, and prints what differs on each one. Nothing is ' +
23
+ 'sent that changes anything, so this is safe to run against every project you have.\n\n' +
24
+ 'Only the attributes the config declares are compared. A project with forty settings the ' +
25
+ 'config never mentions shows nothing for them — that is what makes a baseline safe to point ' +
26
+ 'at projects that already exist.\n\n' +
27
+ 'Entries that exist on the instance but are not in the config are shown as removals, marked ' +
28
+ 'as not pruned unless that section opts into pruning. Seeing what you are choosing not to fix ' +
29
+ 'is most of the value of running this across fifty projects.\n\n' +
30
+ 'Use --fail-on-drift in a scheduled job: it exits 1 when anything differs, so CI can tell you ' +
31
+ 'that something drifted without anyone having to read the output.';
32
+ static examples = [
33
+ '<%= config.bin %> <%= command.id %> --config ./baseline.json',
34
+ '<%= config.bin %> <%= command.id %> --config ./baseline.json --target group/project',
35
+ '<%= config.bin %> <%= command.id %> --config ./baseline.json --fail-on-drift',
36
+ '<%= config.bin %> <%= command.id %> --config ./baseline.json --json | jq .summary',
37
+ ];
38
+ static flags = {
39
+ ...baselineFlags,
40
+ 'fail-on-drift': Flags.boolean({
41
+ summary: 'Exit 1 when any target differs from the baseline.',
42
+ default: false,
43
+ }),
44
+ };
45
+ async run() {
46
+ const config = loadBaselineConfig(this.flags.config);
47
+ const { targets, plan } = await planRun(this.gitlab(), config, {
48
+ concurrency: this.flags.concurrency,
49
+ failFast: this.flags['fail-fast'],
50
+ only: this.flags.target,
51
+ });
52
+ if (!this.jsonEnabled()) {
53
+ // What a run is about to touch is the first question anyone should ask and the last one
54
+ // they should have to guess at.
55
+ this.log(`Targets: ${targets.projects.length} project(s), ${targets.groups.length} group(s).`);
56
+ if (targets.excluded.length > 0)
57
+ this.logSafe(`Excluded: ${targets.excluded.join(', ')}`);
58
+ this.log('');
59
+ this.logSafe(renderPlan(plan));
60
+ }
61
+ const drifted = hasDrift(plan);
62
+ if (this.flags['fail-on-drift'] && drifted) {
63
+ // Deliberately after the output: the point of the flag is to fail a job, not to hide why.
64
+ throw new CliError('The baseline does not match. Run without --fail-on-drift to see the plan.');
65
+ }
66
+ return planToJson(plan);
67
+ }
68
+ }
69
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../src/commands/gitlab/config/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AACvH,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAElE,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,aAAsC;IAC3E,MAAM,CAAmB,OAAO,GAAG,oDAAoD,CAAC;IACxF,MAAM,CAAmB,WAAW,GACzC,2FAA2F;QAC3F,wFAAwF;QACxF,0FAA0F;QAC1F,6FAA6F;QAC7F,qCAAqC;QACrC,6FAA6F;QAC7F,+FAA+F;QAC/F,iEAAiE;QACjE,+FAA+F;QAC/F,kEAAkE,CAAC;IAE9D,MAAM,CAAmB,QAAQ,GAAG;QACzC,8DAA8D;QAC9D,qFAAqF;QACrF,8EAA8E;QAC9E,mFAAmF;KACpF,CAAC;IAEK,MAAM,CAAmB,KAAK,GAAG;QACtC,GAAG,aAAa;QAChB,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC;YAC7B,OAAO,EAAE,mDAAmD;YAC5D,OAAO,EAAE,KAAK;SACf,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE;YAC7D,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;YACnC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YACjC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,wFAAwF;YACxF,gCAAgC;YAChC,IAAI,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,QAAQ,CAAC,MAAM,gBAAgB,OAAO,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,CAAC;YAC/F,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,aAAa,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC1F,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACjC,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,OAAO,EAAE,CAAC;YAC3C,0FAA0F;YAC1F,MAAM,IAAI,QAAQ,CAAC,2EAA2E,CAAC,CAAC;QAClG,CAAC;QAED,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The flags `config plan` and `config apply` share, defined once so the two cannot disagree about
3
+ * what a run means. Both commands read the same file and resolve the same targets; only what they
4
+ * do afterwards differs.
5
+ */
6
+ export declare const baselineFlags: {
7
+ config: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ target: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ concurrency: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
10
+ 'fail-fast': import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
@@ -0,0 +1,50 @@
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 { Flags } from '@oclif/core';
17
+ import { DEFAULT_CONCURRENCY } from '@simplysf/simply-gitlab-core';
18
+ /**
19
+ * The flags `config plan` and `config apply` share, defined once so the two cannot disagree about
20
+ * what a run means. Both commands read the same file and resolve the same targets; only what they
21
+ * do afterwards differs.
22
+ */
23
+ export const baselineFlags = {
24
+ config: Flags.string({
25
+ char: 'c',
26
+ summary: 'Path to the baseline configuration file.',
27
+ required: true,
28
+ }),
29
+ target: Flags.string({
30
+ summary: 'Limit the run to this project path. Repeatable.',
31
+ description: 'Narrows a run without editing the config, for the loop of fixing one project and checking ' +
32
+ 'it again. Naming a project the config does not target is an error rather than a silent ' +
33
+ 'no-op.',
34
+ multiple: true,
35
+ }),
36
+ concurrency: Flags.integer({
37
+ summary: 'How many targets to work on at once.',
38
+ description: 'Small by default. The client already retries a rate-limited request with a capped ' +
39
+ 'Retry-After, so raising this trades a shared instance responsiveness for very little ' +
40
+ 'wall-clock time.',
41
+ default: DEFAULT_CONCURRENCY,
42
+ min: 1,
43
+ max: 16,
44
+ }),
45
+ 'fail-fast': Flags.boolean({
46
+ summary: 'Stop at the first target that fails instead of continuing.',
47
+ default: false,
48
+ }),
49
+ };
50
+ //# sourceMappingURL=baseline-flags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-flags.js","sourceRoot":"","sources":["../../src/shared/baseline-flags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,GAAG;QACT,OAAO,EAAE,0CAA0C;QACnD,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;QACnB,OAAO,EAAE,iDAAiD;QAC1D,WAAW,EACT,4FAA4F;YAC5F,yFAAyF;YACzF,QAAQ;QACV,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC;QACzB,OAAO,EAAE,sCAAsC;QAC/C,WAAW,EACT,oFAAoF;YACpF,uFAAuF;YACvF,kBAAkB;QACpB,OAAO,EAAE,mBAAmB;QAC5B,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,EAAE;KACR,CAAC;IACF,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC;QACzB,OAAO,EAAE,4DAA4D;QACrE,OAAO,EAAE,KAAK;KACf,CAAC;CACH,CAAC"}