Skip to content

Commit ee5745e

Browse files
committed
Fix GCL_VARIABLE and array env vars not splitting multiple values
When setting array-type options via environment variables (e.g. GCL_VARIABLE="VAR1=hello;VAR2=world"), yargs wraps the entire string as a single array element. The getters checked for string type to split, but since yargs already wrapped it as an array, no splitting occurred. Add splitArray helper that splits on semicolons for both string and string[] inputs, and update all array-type getters to use it. Fixes #992
1 parent 6539cff commit ee5745e

2 files changed

Lines changed: 34 additions & 18 deletions

File tree

src/argv.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ export class Argv {
109109
}
110110
}
111111

112+
private splitArray (val: string | string[] | undefined): string[] {
113+
if (val == null) return [];
114+
if (typeof val === "string") return val.split(";");
115+
return val.flatMap((v: string) => v.split(";"));
116+
}
117+
112118
get cwd (): string {
113119
let cwd = this.map.get("cwd") ?? ".";
114120
assert(typeof cwd != "object", "--cwd option cannot be an array");
@@ -140,26 +146,23 @@ export class Argv {
140146
}
141147

142148
get volume (): string[] {
143-
const val = this.map.get("volume") ?? [];
144-
return typeof val == "string" ? val.split(" ") : val;
149+
return this.splitArray(this.map.get("volume"));
145150
}
146151

147152
get network (): string[] {
148-
const val = this.map.get("network") ?? [];
149-
return typeof val == "string" ? val.split(" ") : val;
153+
return this.splitArray(this.map.get("network"));
150154
}
151155

152156
get extraHost (): string[] {
153-
const val = this.map.get("extraHost") ?? [];
154-
return typeof val == "string" ? val.split(" ") : val;
157+
return this.splitArray(this.map.get("extraHost"));
155158
}
156159

157160
get caFile (): string | null {
158161
return this.map.get("caFile") ?? null;
159162
}
160163

161164
get ignoreSchemaPaths (): string[] {
162-
return this.map.get("ignoreSchemaPaths") ?? Argv.default.ignoreSchemaPaths;
165+
return this.splitArray(this.map.get("ignoreSchemaPaths"));
163166
}
164167

165168
get ignorePredefinedVars (): string[] {
@@ -171,30 +174,26 @@ export class Argv {
171174
}
172175

173176
get remoteVariables (): string[] {
174-
const val = this.map.get("remoteVariables") ?? [];
175-
return typeof val == "string" ? val.split(" ") : val;
177+
return this.splitArray(this.map.get("remoteVariables"));
176178
}
177179

178180
get variable (): {[key: string]: string} {
179-
const val = this.map.get("variable");
180181
const variables: {[key: string]: string} = {};
181-
const pairs = typeof val == "string" ? val.split(" ") : val;
182-
(pairs ?? []).forEach((variablePair: string) => {
182+
for (const variablePair of this.splitArray(this.map.get("variable"))) {
183183
const exec = /(?<key>\w*?)(=)(?<value>(.|\n|\r)*)/.exec(variablePair);
184184
if (exec?.groups?.key) {
185185
variables[exec.groups.key] = exec?.groups?.value;
186186
}
187-
});
187+
}
188188
return variables;
189189
}
190190

191191
get unsetVariables (): string[] {
192-
return this.map.get("unsetVariable") ?? [];
192+
return this.splitArray(this.map.get("unsetVariable"));
193193
}
194194

195195
get manual (): string[] {
196-
const val = this.map.get("manual") ?? [];
197-
return typeof val == "string" ? val.split(" ") : val;
196+
return this.splitArray(this.map.get("manual"));
198197
}
199198

200199
get job (): string[] {
@@ -227,8 +226,7 @@ export class Argv {
227226
}
228227

229228
get device (): string[] {
230-
const val = this.map.get("device") ?? [];
231-
return typeof val == "string" ? val.split(" ") : val;
229+
return this.splitArray(this.map.get("device"));
232230
}
233231

234232
get ulimit (): string | null {

tests/test-cases/cli-option-variables/integration.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,21 @@ line string`],
2525
];
2626
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
2727
});
28+
29+
test("cli-option-variables semicolon-separated (GCL_VARIABLE env simulation)", async () => {
30+
const writeStreams = new WriteStreamsMock();
31+
await handler({
32+
cwd: "tests/test-cases/cli-option-variables",
33+
job: ["test-job"],
34+
variable: ["CLI_VAR=hello world;CLI_VAR_DOT=dotdot", `CLI_MULTILINE=This is a multi
35+
line string`],
36+
}, writeStreams);
37+
38+
const expected = [
39+
chalk`{blueBright test-job} {greenBright >} hello world`,
40+
chalk`{blueBright test-job} {greenBright >} dotdot`,
41+
chalk`{blueBright test-job} {greenBright >} This is a multi`,
42+
chalk`{blueBright test-job} {greenBright >} line string`,
43+
];
44+
expect(writeStreams.stdoutLines).toEqual(expect.arrayContaining(expected));
45+
});

0 commit comments

Comments
 (0)