diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/in_source_config/index.ts b/packages/zip-it-and-ship-it/src/runtimes/node/in_source_config/index.ts index 394a0de7b5..e8de69941a 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/in_source_config/index.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/in_source_config/index.ts @@ -1,3 +1,5 @@ +import { dirname } from 'path' + import type { ArgumentPlaceholder, Expression, SpreadElement, JSXNamespacedName } from '@babel/types' import mergeOptions from 'merge-options' import { z } from 'zod' @@ -215,10 +217,26 @@ export const parseSource = (source: string, { functionName }: FindISCDeclaration } export const augmentFunctionConfig = ( + mainFile: string, tomlConfig: FunctionConfig, inSourceConfig: InSourceConfig = {}, -): FunctionConfig & InSourceConfig => { - return mergeOptions.call({ concatArrays: true }, tomlConfig, inSourceConfig) +) => { + const mergedConfig = mergeOptions.call({ concatArrays: true }, tomlConfig, inSourceConfig) as FunctionConfig & + InSourceConfig + + // We can't simply merge included files from the TOML and from in-source + // configuration because their globs are relative to different base paths. + // In the future, we could shift things around so we resolve each glob + // relative to the right base, but for now we say that included files in + // the source override any files defined in the TOML. It doesn't make a lot + // of sense to be defining include files for a framework-generated function + // in the TOML anyway. + if (inSourceConfig?.includedFiles && inSourceConfig.includedFiles.length !== 0) { + mergedConfig.includedFiles = inSourceConfig.includedFiles + mergedConfig.includedFilesBasePath = dirname(mainFile) + } + + return mergedConfig } export type ISCHandlerArg = ArgumentPlaceholder | Expression | SpreadElement | JSXNamespacedName diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/index.ts b/packages/zip-it-and-ship-it/src/runtimes/node/index.ts index 69ed26e594..bf94d1f343 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/index.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/index.ts @@ -65,7 +65,7 @@ const zipFunction: ZipFunction = async function ({ const staticAnalysisResult = await parseFile(mainFile, { functionName: name }) const runtimeAPIVersion = staticAnalysisResult.runtimeAPIVersion === 2 ? 2 : 1 - const mergedConfig = augmentFunctionConfig(config, staticAnalysisResult.config) + const mergedConfig = augmentFunctionConfig(mainFile, config, staticAnalysisResult.config) const pluginsModulesPath = await getPluginsModulesPath(srcDir) const bundlerName = await getBundlerName({ config: mergedConfig, diff --git a/packages/zip-it-and-ship-it/tests/fixtures-esm/v2-api-included-files/function.js b/packages/zip-it-and-ship-it/tests/fixtures-esm/v2-api-included-files/netlify/functions/function.js similarity index 80% rename from packages/zip-it-and-ship-it/tests/fixtures-esm/v2-api-included-files/function.js rename to packages/zip-it-and-ship-it/tests/fixtures-esm/v2-api-included-files/netlify/functions/function.js index c9964292d1..ff900f0e9a 100644 --- a/packages/zip-it-and-ship-it/tests/fixtures-esm/v2-api-included-files/function.js +++ b/packages/zip-it-and-ship-it/tests/fixtures-esm/v2-api-included-files/netlify/functions/function.js @@ -6,5 +6,5 @@ export default async () => }) export const config = { - includedFiles: ['blog/author*'], + includedFiles: ['../../blog/post*'], } diff --git a/packages/zip-it-and-ship-it/tests/v2api.test.ts b/packages/zip-it-and-ship-it/tests/v2api.test.ts index acbf5b0462..c06449f549 100644 --- a/packages/zip-it-and-ship-it/tests/v2api.test.ts +++ b/packages/zip-it-and-ship-it/tests/v2api.test.ts @@ -5,6 +5,7 @@ import { promisify } from 'util' import merge from 'deepmerge' import glob from 'glob' +import { pathExists } from 'path-exists' import semver from 'semver' import { dir as getTmpDir } from 'tmp-promise' import { afterEach, describe, expect, test, vi } from 'vitest' @@ -598,39 +599,39 @@ describe.runIf(semver.gte(nodeVersion, '18.13.0'))('V2 functions API', () => { }, ) - testMany( - 'Includes in the bundle files included in the TOML and in the function source', - ['bundler_default'], - async (options) => { - const fixtureName = 'v2-api-included-files' - const { files, tmpDir } = await zipFixture(fixtureName, { - fixtureDir: FIXTURES_ESM_DIR, - opts: merge(options, { - archiveFormat: ARCHIVE_FORMAT.NONE, - config: { - '*': { - includedFiles: ['blog/post*'], - }, + test('Includes in the bundle files included in the function source', async () => { + const fixtureName = 'v2-api-included-files' + const { files, tmpDir } = await zipFixture(`${fixtureName}/netlify/functions`, { + fixtureDir: FIXTURES_ESM_DIR, + opts: { + archiveFormat: ARCHIVE_FORMAT.NONE, + basePath: resolve(FIXTURES_ESM_DIR, fixtureName), + config: { + '*': { + includedFiles: ['blog/author*'], }, - }), - }) + }, + }, + }) - const [{ name: archive, entryFilename, includedFiles, runtimeAPIVersion }] = files - const func = await importFunctionFile(`${tmpDir}/${archive}/${entryFilename}`) - const { body: bodyStream, multiValueHeaders = {}, statusCode } = await invokeLambda(func) - const body = await readAsBuffer(bodyStream) + const [{ name: archive, entryFilename, includedFiles, runtimeAPIVersion }] = files + const func = await importFunctionFile(`${tmpDir}/${archive}/${entryFilename}`) + const { body: bodyStream, multiValueHeaders = {}, statusCode } = await invokeLambda(func) + const body = await readAsBuffer(bodyStream) - expect(body).toBe('