Repository navigation
Expand file tree
/
Copy pathdeprecated-env.ts
More file actions
319 lines (301 loc) · 10.9 KB
/
Copy pathdeprecated-env.ts
File metadata and controls
319 lines (301 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
function shownEnvValue(rawValue: string): string {
const singleLine = rawValue.replace(/[\r\n]/g, " ");
if (singleLine.length <= 80) {
return singleLine;
}
return `${singleLine.slice(0, 77)}...`;
}
const REMOVAL_VERSION = "v3.0.0";
const DEPRECATION_NOTICE_URL = "https://github.com/zereight/gitlab-mcp/issues/815";
// USE_PIPELINE exposes these two tools, but they live in the `ci` toolset, not `pipelines`.
// Suggesting `ci` would also turn on catalog tools the flag does not expose.
const LEGACY_TOOLS_OUTSIDE_NAMED_TOOLSET: Readonly<Record<string, string>> = {
pipelines: "validate_ci_lint,validate_project_ci_lint",
};
function explicitToolsets(raw: string | undefined): string | undefined {
if (raw === undefined) {
return undefined;
}
const trimmed = raw.trim();
if (trimmed === "") {
return undefined;
}
return trimmed;
}
function isAllToolsets(raw: string): boolean {
return raw.trim().toLowerCase() === "all";
}
function settingName(envName: string, cliFlag: string, fromCli: boolean): string {
if (fromCli) {
return `\`--${cliFlag}\` (${envName})`;
}
return envName;
}
function gitlabToolsAssignment(
extraTools: string,
toolsRaw: string | undefined,
toolsFromCli: boolean
): string {
const prefix = toolsFromCli ? "--tools=" : "GITLAB_TOOLS=";
const existing = explicitToolsets(toolsRaw);
if (existing === undefined) {
return `${prefix}${extraTools}`;
}
const names = existing
.split(",")
.map(part => part.trim())
.filter(part => part.length > 0);
const merged = extraTools.split(",").reduce<string[]>((current, tool) => {
if (current.includes(tool)) {
return current;
}
return [...current, tool];
}, names);
return `${prefix}${merged.join(",")}`;
}
function legacyToolsetHint(
toolset: string,
toolsetsRaw: string | undefined,
toolsetsFromCli: boolean,
toolsRaw: string | undefined,
toolsFromCli: boolean,
optional: boolean
): string {
const extraTools = LEGACY_TOOLS_OUTSIDE_NAMED_TOOLSET[toolset];
const toolsAssignment =
extraTools === undefined
? undefined
: gitlabToolsAssignment(extraTools, toolsRaw, toolsFromCli);
const listed = explicitToolsets(toolsetsRaw);
const toolsetsLabel = toolsetsFromCli && listed !== undefined ? "--toolsets" : "GITLAB_TOOLSETS";
if (listed !== undefined) {
const shown = shownEnvValue(listed);
// parseEnabledToolsets treats only the exact value "all" as every toolset.
// "all,pipelines" is not "all"; unknown token "all" is dropped and pipelines remains.
if (isAllToolsets(listed)) {
return `Keep the existing ${toolsetsLabel} value ("${shown}") and remove the deprecated setting`;
}
const extra = toolsAssignment === undefined ? "" : ` and set ${toolsAssignment}`;
if (optional) {
return (
`Add \`${toolset}\` to the existing ${toolsetsLabel} list ("${shown}")${extra} ` +
"only if you want those tools"
);
}
return `Add \`${toolset}\` to the existing ${toolsetsLabel} list ("${shown}")${extra} instead`;
}
// An explicit toolset list replaces the default toolsets; it does not merge.
// Legacy USE_* flags add tools on top of defaults, so the hint must keep `core`
// only when the user has not set a toolset list.
const toolsets = `GITLAB_TOOLSETS=core,${toolset}`;
const replacement =
toolsAssignment === undefined ? toolsets : `${toolsets} and ${toolsAssignment}`;
if (optional) {
return `Set ${replacement} only if you want those tools in addition to core`;
}
return `Use ${replacement} instead`;
}
function legacyToolsetWarning(
envName: string,
cliFlag: string,
fromCli: boolean,
rawValue: string,
toolset: string,
toolsetsRaw: string | undefined,
toolsetsFromCli: boolean,
toolsRaw: string | undefined,
toolsFromCli: boolean
): string {
const name = settingName(envName, cliFlag, fromCli);
if (rawValue === "true") {
return (
`${name} is deprecated and will be removed in ${REMOVAL_VERSION}. ` +
`${legacyToolsetHint(toolset, toolsetsRaw, toolsetsFromCli, toolsRaw, toolsFromCli, false)}.`
);
}
const shown = shownEnvValue(rawValue);
return (
`${name} is set to "${shown}" and is deprecated and will be removed in ${REMOVAL_VERSION}. ` +
`This value does not enable the ${toolset} toolset. Remove it. ` +
`${legacyToolsetHint(toolset, toolsetsRaw, toolsetsFromCli, toolsRaw, toolsFromCli, true)}.`
);
}
export interface DeprecatedEnvInput {
readOnlyMode: boolean;
/** Raw `--read-only` / GITLAB_READ_ONLY_MODE value, including non-true values such as "false". */
readOnlyRaw?: string;
readOnlyFromCli?: boolean;
/** Value the user set for GITLAB_PERMISSION_MODE / --permission-mode, before GITLAB_READ_ONLY_MODE overrides it. */
permissionModeRaw: string | undefined;
allowedGroupsRaw: string | undefined;
allowedGroupsFromCli?: boolean;
oauthAllowedGroupsRaw: string | undefined;
useWikiRaw: string | undefined;
useWikiFromCli?: boolean;
useMilestoneRaw: string | undefined;
useMilestoneFromCli?: boolean;
usePipelineRaw: string | undefined;
usePipelineFromCli?: boolean;
/** Effective GITLAB_TOOLSETS / --toolsets value when the user set one. */
toolsetsRaw?: string;
/** True when toolsetsRaw came from --toolsets, which wins over GITLAB_TOOLSETS. */
toolsetsFromCli?: boolean;
/** Effective GITLAB_TOOLS / --tools value when the user set one. */
toolsRaw?: string;
/** True when toolsRaw came from --tools, which wins over GITLAB_TOOLS. */
toolsFromCli?: boolean;
}
function readOnlyRawValue(input: DeprecatedEnvInput): string | undefined {
if (input.readOnlyRaw !== undefined && input.readOnlyRaw !== "") {
return input.readOnlyRaw;
}
if (input.readOnlyMode) {
return "true";
}
return undefined;
}
function readOnlyWarning(input: DeprecatedEnvInput): string | undefined {
const raw = readOnlyRawValue(input);
if (raw === undefined) {
return undefined;
}
const name = settingName("GITLAB_READ_ONLY_MODE", "read-only", input.readOnlyFromCli === true);
if (raw === "true") {
const conflict =
input.permissionModeRaw !== undefined && input.permissionModeRaw !== "readonly"
? ` It OVERRIDES the configured permission mode "${input.permissionModeRaw}"; the server runs as "readonly".`
: "";
return (
`${name} is deprecated and will be removed in ${REMOVAL_VERSION}. ` +
`Use GITLAB_PERMISSION_MODE=readonly or --permission-mode=readonly instead.${conflict}`
);
}
return (
`${name} is set to "${shownEnvValue(raw)}" and is deprecated and will be removed in ${REMOVAL_VERSION}. ` +
"This value does not enable legacy read-only mode. The effective permission mode comes from GITLAB_PERMISSION_MODE or --permission-mode. Remove it."
);
}
/**
* Builds startup warnings for deprecated env vars / CLI flags.
* Pure function so the messages and conflict detection are unit-testable.
*/
export function getDeprecatedEnvWarnings(input: DeprecatedEnvInput): string[] {
const warnings: string[] = [];
const readOnly = readOnlyWarning(input);
if (readOnly !== undefined) {
warnings.push(readOnly);
}
if (input.allowedGroupsRaw) {
const name = settingName(
"GITLAB_ALLOWED_GROUPS",
"allowed-groups",
input.allowedGroupsFromCli === true
);
warnings.push(
input.oauthAllowedGroupsRaw
? `${name} is deprecated and ignored because GITLAB_OAUTH_ALLOWED_GROUPS is set. Remove it. It will be removed in ${REMOVAL_VERSION}.`
: `${name} is deprecated and will be removed in ${REMOVAL_VERSION}. Use GITLAB_OAUTH_ALLOWED_GROUPS instead.`
);
}
const legacyToolsetFlags: ReadonlyArray<{
readonly rawValue: string | undefined;
readonly envName: string;
readonly cliFlag: string;
readonly fromCli: boolean;
readonly toolset: string;
}> = [
{
rawValue: input.useWikiRaw,
envName: "USE_GITLAB_WIKI",
cliFlag: "use-wiki",
fromCli: input.useWikiFromCli === true,
toolset: "wiki",
},
{
rawValue: input.useMilestoneRaw,
envName: "USE_MILESTONE",
cliFlag: "use-milestone",
fromCli: input.useMilestoneFromCli === true,
toolset: "milestones",
},
{
rawValue: input.usePipelineRaw,
envName: "USE_PIPELINE",
cliFlag: "use-pipeline",
fromCli: input.usePipelineFromCli === true,
toolset: "pipelines",
},
];
for (const flag of legacyToolsetFlags) {
// An empty value (e.g. `USE_PIPELINE=${USE_PIPELINE}` in docker-compose with the
// variable unset) is not a configured flag, matching GITLAB_READ_ONLY_MODE above.
if (flag.rawValue !== undefined && flag.rawValue !== "") {
warnings.push(
legacyToolsetWarning(
flag.envName,
flag.cliFlag,
flag.fromCli,
flag.rawValue,
flag.toolset,
input.toolsetsRaw,
input.toolsetsFromCli === true,
input.toolsRaw,
input.toolsFromCli === true
)
);
}
}
return warnings.map(warning => `${warning} See ${DEPRECATION_NOTICE_URL} for migration details.`);
}
function readSuppliedSetting(
parsedArgs: Readonly<Record<string, string>>,
env: NodeJS.ProcessEnv,
cliKey: string,
envKey: string
): string | undefined {
return parsedArgs[cliKey] || env[envKey];
}
/**
* Warning snapshot for one command. CLI flags in `parsedArgs` win over `env`,
* matching getConfig, and neither source is read from the process globals.
*/
export function deprecatedEnvInputFromSources(
parsedArgs: Readonly<Record<string, string>>,
env: NodeJS.ProcessEnv
): DeprecatedEnvInput {
const readOnlyRaw = readSuppliedSetting(parsedArgs, env, "read-only", "GITLAB_READ_ONLY_MODE");
return {
readOnlyMode: readOnlyRaw === "true",
readOnlyRaw,
readOnlyFromCli: Boolean(parsedArgs["read-only"]),
permissionModeRaw: readSuppliedSetting(
parsedArgs,
env,
"permission-mode",
"GITLAB_PERMISSION_MODE"
),
allowedGroupsRaw: readSuppliedSetting(
parsedArgs,
env,
"allowed-groups",
"GITLAB_ALLOWED_GROUPS"
),
allowedGroupsFromCli: Boolean(parsedArgs["allowed-groups"]),
oauthAllowedGroupsRaw: readSuppliedSetting(
parsedArgs,
env,
"oauth-allowed-groups",
"GITLAB_OAUTH_ALLOWED_GROUPS"
),
useWikiRaw: readSuppliedSetting(parsedArgs, env, "use-wiki", "USE_GITLAB_WIKI"),
useWikiFromCli: Boolean(parsedArgs["use-wiki"]),
useMilestoneRaw: readSuppliedSetting(parsedArgs, env, "use-milestone", "USE_MILESTONE"),
useMilestoneFromCli: Boolean(parsedArgs["use-milestone"]),
usePipelineRaw: readSuppliedSetting(parsedArgs, env, "use-pipeline", "USE_PIPELINE"),
usePipelineFromCli: Boolean(parsedArgs["use-pipeline"]),
toolsetsRaw: readSuppliedSetting(parsedArgs, env, "toolsets", "GITLAB_TOOLSETS"),
toolsetsFromCli: Boolean(parsedArgs["toolsets"]),
toolsRaw: readSuppliedSetting(parsedArgs, env, "tools", "GITLAB_TOOLS"),
toolsFromCli: Boolean(parsedArgs["tools"]),
};
}