-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ui] Upgrade yaml library, improve config merge behavior (#20055)
## Summary & Motivation This PR aims to address #19668 (but doesn't entirely fix it): Context: In the launchpad, there are several scenarios where we parse the current YAML, modify it as a JS object tree, and serialize it back to YAML. This is fundamentally undesirable because some YAML values (eg: 5.0) experience type coercion (eg: to 5) because JS does not have a Float type, etc. Fully fixing this would require changing the YAML merge logic to use YAML ASTs, but that's complex and we express config defaults as JS objects, so it wouldn't entirely resolve the "5.0 to 5" issue. This PR fixes two of the more straightforward bugs in the "parse, merge, stringify" workflow: - The deepmerge library changed in v3+ to concatenate arrays by default rather than combining them (so [a,b,c] + [c,d,e] = [a,b,c,c,d,e]). This changes it to the expected ([a,b,c,d,e]), and means that merging two identical arrays does nothing to them. - The yaml stringify method tries to be "lean" with quotes, but can un-quote some values that other YAML parsers parse as other types. The example called out in #19668 was "5:30" becoming 5:30, which is a Sexagesimal base-60 number in python. (This has been called out as awful behavior before: https://news.ycombinator.com/item?id=26679229). I changed the serialize call to explicitly maintain quotes on all string values, which looks a bit ugly if you're a YAML purist but will avoid these cases. ## How I Tested These Changes I broke out a yamlMerge helper and wrote tests for the cases above, verified they failed and then fixed them --------- Co-authored-by: bengotow <[email protected]>
- Loading branch information
Showing
6 changed files
with
92 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
js_modules/dagster-ui/packages/ui-core/src/launchpad/__tests__/yamlUtils.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import {mergeYaml} from '../yamlUtils'; | ||
|
||
describe('yamlUtils.mergeYaml', () => { | ||
it('should not duplicate array contents', () => { | ||
const a = `hello: | ||
- 1 | ||
- a: "object" | ||
- 3`; | ||
|
||
const b = `hello: | ||
- 1 | ||
- a: "object" | ||
- 4`; | ||
|
||
const c = `hello: | ||
- 1 | ||
- a: 'object' | ||
- 3 | ||
- 4 | ||
`; | ||
expect(mergeYaml(a, b)).toEqual(c); | ||
}); | ||
|
||
it('should quote strings that may be mis-interpreted', () => { | ||
const a = `hello: "5:30"`; | ||
const b = `world: 4`; | ||
const c = `hello: '5:30'\nworld: 4\n`; | ||
expect(mergeYaml(a, b)).toEqual(c); | ||
}); | ||
}); |
46 changes: 46 additions & 0 deletions
46
js_modules/dagster-ui/packages/ui-core/src/launchpad/yamlUtils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import merge from 'deepmerge'; | ||
import * as yaml from 'yaml'; | ||
|
||
export const sanitizeConfigYamlString = (yamlString: string) => (yamlString || '').trim() || '{}'; | ||
|
||
/** | ||
* Utility function to merge two YAML documents: | ||
* - Stringify string values with quotes. Avoids known issues with "5:30" becoming 5:30 which parses as a Sexagesimal number | ||
* - When merging arrays, combine rather than concatenate (the default deepmerge behavior) | ||
* - | ||
*/ | ||
export function mergeYaml( | ||
base: string | Record<string, any>, | ||
overrides: string | Record<string, any>, | ||
extraOpts?: yaml.SchemaOptions, | ||
) { | ||
const baseObj = typeof base === 'string' ? yaml.parse(sanitizeConfigYamlString(base)) : base; | ||
|
||
const overridesObj = | ||
typeof overrides === 'string' ? yaml.parse(sanitizeConfigYamlString(overrides)) : overrides; | ||
|
||
const arrayCombineMerge: merge.Options['arrayMerge'] = (target, source, options) => { | ||
const destination = target.slice(); | ||
|
||
source.forEach((item, index) => { | ||
if (typeof destination[index] === 'undefined') { | ||
destination[index] = options?.cloneUnlessOtherwiseSpecified(item, options); | ||
} else if (options?.isMergeableObject(item)) { | ||
destination[index] = merge(target[index], item, options); | ||
} else if (target.indexOf(item) === -1) { | ||
destination.push(item); | ||
} | ||
}); | ||
return destination; | ||
}; | ||
|
||
const mergedObj = merge(baseObj, overridesObj, { | ||
arrayMerge: arrayCombineMerge, | ||
}); | ||
|
||
return yaml.stringify(mergedObj, { | ||
defaultKeyType: 'PLAIN', | ||
defaultStringType: 'QUOTE_SINGLE', | ||
...extraOpts, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0759886
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deploy preview for dagit-storybook ready!
✅ Preview
https://dagit-storybook-m6iycnkdy-elementl.vercel.app
Built with commit 0759886.
This pull request is being automatically deployed with vercel-action
0759886
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deploy preview for dagit-core-storybook ready!
✅ Preview
https://dagit-core-storybook-7m0073kzb-elementl.vercel.app
Built with commit 0759886.
This pull request is being automatically deployed with vercel-action