Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update method for merging ISC with TOML config #5712

Merged
merged 9 commits into from
Jun 14, 2024

Conversation

eduardoboucas
Copy link
Member

@eduardoboucas eduardoboucas commented Jun 13, 2024

Summary

In preparation for #5668, this changes the way we merge configuration properties from the TOML with in-source configuration. There was a lot of manual work involved in validating properties, and a lot of duplication in reading properties from the regular function config object and in-source configuration.

This PR makes use of zod to create a schema for the different sources of config, and parsing/validating them accordingly.

As part of this, we now allow includedFiles, externalNodeModules, ignoredNodeModules and nodeBundler to be defined in-source.

Part of COM-798.

@eduardoboucas eduardoboucas requested review from a team as code owners June 13, 2024 15:20
Copy link
Contributor

This pull request adds or modifies JavaScript (.js, .cjs, .mjs) files.
Consider converting them to TypeScript.

@eduardoboucas
Copy link
Member Author

Still some failing tests. Will sort tomorrow.

Copy link
Contributor

@Skn0tt Skn0tt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite a big change, but it looks good to me! I've left a couple of comments, all of them nits.

export const functionConfig = z.object({
externalNodeModules: z.array(z.string()).optional().catch([]),
generator: z.string().optional().catch(undefined),
includedFiles: z.array(z.string()).optional().catch([]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure why, but using undefined as the fallback for an optional value makes more sense to me.

Suggested change
includedFiles: z.array(z.string()).optional().catch([]),
includedFiles: z.array(z.string()).optional().catch(undefined),

includedFiles: z.array(z.string()).optional().catch([]),
includedFilesBasePath: z.string().optional().catch(undefined),
ignoredNodeModules: z.array(z.string()).optional().catch([]),
name: z.string().optional().catch(undefined),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a lot of duplication in this. does mit make sense to extract z.string().optional().... into a few constants, just so that there's fewer characters on the screen? It reads very dense right now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean, but at the same time I don't know what would be the criteria for extracting something into a constant. We could have optionalString = z.string()).optional(), but is that really saving a lot of characters? We could add .catch(undefined) to that, but what do we do about the strings where we don't want to have a catch? I'm not super convinced this would help a lot, tbh.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any strings where we don't have a catch, though?

Maybe it'd already help to add a few empty lines in between the different parameters. That'd make it less of a uniform wall of text.

packages/zip-it-and-ship-it/src/rate_limit.ts Show resolved Hide resolved
*/
export const getTrafficRulesConfig = (input: RateLimit): TrafficRules | undefined => {
const { windowSize, windowLimit, algorithm, aggregateBy, action, to } = input
const rateLimitAgg = Array.isArray(aggregateBy) ? aggregateBy : [rateLimitAggregator.Enum.domain]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this incorrectly turns rateLimitAggregator: "ip" into "domain". Should it be this instead?

Suggested change
const rateLimitAgg = Array.isArray(aggregateBy) ? aggregateBy : [rateLimitAggregator.Enum.domain]
const rateLimitAgg = Array.isArray(aggregateBy) ? aggregateBy : [aggregateBy]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going by the current implementation:

const rateLimitAgg = Array.isArray(aggregateBy) ? aggregateBy : [RateLimitAggregator.Domain]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, then let's keep the fixing of that to a different PR. @paulo I think you wrote this (and I reviewed ...), what are your thoughts on it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thought process at the time was to not fail the build and just use the default since it's not an obligatory field, but I'm now regretting it. If I could do it all over again I think I'd just fail the build if aggregateBy is not an array (if defined, not an obligatory field), but leaving the current logic is also ok

runtimeAPIVersion?: number
}

interface FindISCDeclarationsOptions {
functionName: string
}

const httpMethods = z.preprocess(
(input) => (typeof input === 'string' ? input.toUpperCase() : input),
z.enum(['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE', 'HEAD']),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this list is exhaustive? What about uncommon methods like TRACE or PROPFIND? Might be worth doing this change in a separate PR and explore that first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the methods that our CDN supports, everything else is blocked:

var validMethods = map[string]struct{}{
	"ACL":               {},
	"BASELINE-CONTROL":  {},
	"BIND":              {},
	"CHECKIN":           {},
	"CHECKOUT":          {},
	"COPY":              {},
	"DELETE":            {},
	"GET":               {},
	"HEAD":              {},
	"LABEL":             {},
	"LINK":              {},
	"LOCK":              {},
	"MERGE":             {},
	"MKACTIVITY":        {},
	"MKCALENDAR":        {},
	"MKCOL":             {},
	"MKREDIRECTREF":     {},
	"MKWORKSPACE":       {},
	"MOVE":              {},
	"OPTIONS":           {},
	"ORDERPATCH":        {},
	"PATCH":             {},
	"POST":              {},
	"PRI":               {},
	"PROPFIND":          {},
	"PROPPATCH":         {},
	"PUT":               {},
	"REBIND":            {},
	"REPORT":            {},
	"SEARCH":            {},
	"UNBIND":            {},
	"UNCHECKOUT":        {},
	"UNLINK":            {},
	"UNLOCK":            {},
	"UPDATE":            {},
	"UPDATEREDIRECTREF": {},
	"VERSION-CONTROL":   {},
	"*":                 {},
}

if (configExport.rateLimit !== undefined) {
result.trafficRules = getTrafficRulesConfig(configExport.rateLimit, functionName)
try {
const iscValues = isc.parse(configExport)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

zod really is an incredibly nice piece of code.

Copy link
Member Author

@eduardoboucas eduardoboucas Jun 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think it's going to make our lives easier!

@@ -2,7 +2,8 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist" /* Specify an output folder for all emitted files. */,
"esModuleInterop": true
"esModuleInterop": true,
"strict": true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@eduardoboucas eduardoboucas merged commit 251ffcc into main Jun 14, 2024
37 checks passed
@eduardoboucas eduardoboucas deleted the feat/zisi-merge-config branch June 14, 2024 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants