[config] stop merging arrays from multiple configs (#161884)

## Summary

Fix an unwanted behavior of the config merging logic, that was merging
arrays the same way objects are merged.

E.g the output of `getConfigFromFiles(file1, file2)` with 

```yaml
### file 1
array: [1, 2, 3]
obj_array:
  - id: 1
  - id: 2

### file 2
array: [4]
obj_array:
  - id: 3
```

was 

```yaml
array: [4, 2, 3]
obj_array:
  - id: 3
  - id: 2
```

instead of 

```yaml
array: [4]
obj_array:
  - id: 3
```

Which is causing problems when merging the default, serverless,
serverless project and dev file in some scenarios.
This commit is contained in:
Pierre Gayvallet 2023-07-14 12:57:58 +02:00 committed by GitHub
parent 37b48d344f
commit a9f6e03da7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 2 deletions

View file

@ -0,0 +1,10 @@
foo: 1
bar: 3
arr1: [1, 2, 3]
arr2: [42, 90]
nested:
str1: "foo"
str2: "hello"
obj_array:
- id: 1
- id: 2

View file

@ -0,0 +1,8 @@
foo: 2
arr1: [4, 5]
arr2: []
nested:
str1: "bar"
str3: "dolly"
obj_array:
- id: 3

View file

@ -22,6 +22,28 @@ Object {
}
`;
exports[`merging two configs 1`] = `
Object {
"arr1": Array [
4,
5,
],
"arr2": Array [],
"bar": 3,
"foo": 2,
"nested": Object {
"str1": "bar",
"str2": "hello",
"str3": "dolly",
},
"obj_array": Array [
Object {
"id": 3,
},
],
}
`;
exports[`reads and merges multiple yaml files from file system and parses to json 1`] = `
Object {
"abc": Object {

View file

@ -59,6 +59,11 @@ test('throws parsing another config with forbidden paths', () => {
).toThrowErrorMatchingInlineSnapshot(`"Forbidden path detected: test.hello.__proto__"`);
});
test('merging two configs', () => {
const config = getConfigFromFiles([fixtureFile('merge_1.yml'), fixtureFile('merge_2.yml')]);
expect(config).toMatchSnapshot();
});
describe('different cwd()', () => {
const originalCwd = process.cwd();
const tempCwd = resolve(__dirname);

View file

@ -27,17 +27,29 @@ function replaceEnvVarRefs(val: string) {
}
function merge(target: Record<string, any>, value: any, key?: string) {
if ((isPlainObject(value) || Array.isArray(value)) && Object.keys(value).length > 0) {
if (isPlainObject(value) && Object.keys(value).length > 0) {
for (const [subKey, subVal] of Object.entries(value)) {
merge(target, subVal, key ? `${key}.${subKey}` : subKey);
}
} else if (key !== undefined) {
set(target, key, typeof value === 'string' ? replaceEnvVarRefs(value) : value);
set(target, key, recursiveReplaceEnvVar(value));
}
return target;
}
function recursiveReplaceEnvVar(value: any) {
if (isPlainObject(value) || Array.isArray(value)) {
for (const [subKey, subVal] of Object.entries(value)) {
set(value, subKey, recursiveReplaceEnvVar(subVal));
}
}
if (typeof value === 'string') {
return replaceEnvVarRefs(value);
}
return value;
}
/** @internal */
export const getConfigFromFiles = (configFiles: readonly string[]) => {
let mergedYaml = {};