Skip to content

Commit

Permalink
fix: determine duplicate function precedence based on extension (#5623)
Browse files Browse the repository at this point in the history
* fix: determine duplicate function precedence based on extension

* test: add test for duplicate function precedence

* feat: reverse functions array to keep function precedence

* feat: reverse functions array to keep function precedence

* feat: reverse the way we pass sourcedirectories to match reversed order

* Update src/lib/functions/registry.mjs

Co-authored-by: Eduardo Bouças <mail@eduardoboucas.com>

* Update src/lib/functions/registry.mjs

Co-authored-by: Eduardo Bouças <mail@eduardoboucas.com>

---------

Co-authored-by: Eduardo Bouças <mail@eduardoboucas.com>
  • Loading branch information
khendrikse and eduardoboucas authored Apr 13, 2023
1 parent 17605fc commit 169ecad
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 4 deletions.
5 changes: 4 additions & 1 deletion src/lib/functions/registry.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,10 @@ export class FunctionsRegistry {
await Promise.all(deletedFunctions.map((func) => this.unregisterFunction(func.name)))

await Promise.all(
functions.map(async ({ displayName, mainFile, name, runtime: runtimeName }) => {
// zip-it-and-ship-it returns an array sorted based on which extension should have precedence,
// where the last ones precede the previous ones. This is why
// we reverse the array so we get the right functions precedence in the CLI.
functions.reverse().map(async ({ displayName, mainFile, name, runtime: runtimeName }) => {
const runtime = runtimes[runtimeName]

// If there is no matching runtime, it means this function is not yet
Expand Down
4 changes: 2 additions & 2 deletions src/lib/functions/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ export const startFunctionsServer = async (options) => {
functionsDirectories.push(distPath)
}
} else {
// The order of the function directories matters. Leftmost directories take
// The order of the function directories matters. Rightmost directories take
// precedence.
const sourceDirectories = [settings.functions, internalFunctionsDir].filter(Boolean)
const sourceDirectories = [internalFunctionsDir, settings.functions].filter(Boolean)

functionsDirectories.push(...sourceDirectories)
}
Expand Down
68 changes: 67 additions & 1 deletion tests/unit/lib/functions/registry.test.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
import { expect, test, vi } from 'vitest'
import { mkdir, mkdtemp, writeFile } from 'fs/promises'
import { tmpdir } from 'os'
import { join } from 'path'

import { describe, expect, test, vi } from 'vitest'

import { FunctionsRegistry } from '../../../../src/lib/functions/registry.mjs'
import { watchDebounced } from '../../../../src/utils/command-helpers.mjs'

const duplicateFunctions = [
{
filename: 'hello.js',
content: `exports.handler = async (event) => ({ statusCode: 200, body: JSON.stringify({ message: 'Hello World from .js' }) })`,
},
{
filename: 'hello.ts',
content: `exports.handler = async (event) => ({ statusCode: 200, body: JSON.stringify({ message: 'Hello World from .ts' }) })`,
},
{
filename: 'hello2.js',
content: `exports.handler = async (event) => ({ statusCode: 200, body: JSON.stringify({ message: 'Hello World from .ts' }) })`,
},
{
filename: 'hello2/main.go',
subDir: 'hello2',
content: `package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, world from a go function!")
}
`,
},
]

vi.mock('../../../../src/utils/command-helpers.mjs', async () => {
const helpers = await vi.importActual('../../../../src/utils/command-helpers.mjs')

Expand Down Expand Up @@ -35,6 +67,40 @@ test('registry should only pass functions config to zip-it-and-ship-it', async (
await prepareDirectoryScanStub.mockRestore()
})

describe('the registry handles duplicate functions based on extension precedence', () => {
test('where .js takes precedence over .go, and .go over .ts', async () => {
const projectRoot = await mkdtemp(join(tmpdir(), 'functions-extension-precedence'))
const functionsDirectory = join(projectRoot, 'functions')
await mkdir(functionsDirectory)

duplicateFunctions.forEach(async (func) => {
if (func.subDir) {
const subDir = join(functionsDirectory, func.subDir)
await mkdir(subDir)
}
const file = join(functionsDirectory, func.filename)
await writeFile(file, func.content)
})
const functionsRegistry = new FunctionsRegistry({
projectRoot,
config: {},
timeouts: { syncFunctions: 1, backgroundFunctions: 1 },
settings: { port: 8888 },
})
const prepareDirectoryScanStub = vi.spyOn(FunctionsRegistry, 'prepareDirectoryScan').mockImplementation(() => {})
const setupDirectoryWatcherStub = vi.spyOn(functionsRegistry, 'setupDirectoryWatcher').mockImplementation(() => {})

await functionsRegistry.scan([functionsDirectory])
const { functions } = functionsRegistry

expect(functions.get('hello').runtime.name).toBe('js')
expect(functions.get('hello2').runtime.name).toBe('go')

await setupDirectoryWatcherStub.mockRestore()
await prepareDirectoryScanStub.mockRestore()
})
})

test('should add included_files to watcher', async () => {
const registry = new FunctionsRegistry({})
const func = {
Expand Down

1 comment on commit 169ecad

@github-actions
Copy link

Choose a reason for hiding this comment

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

📊 Benchmark results

  • Package size: 313 MB

Please sign in to comment.