diff --git a/.gitignore b/.gitignore index d2b57d1fcc..35b8b8eb90 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,6 @@ packages/*/lib/ !**/fixtures/**/functions_*/.netlify !**/fixtures/**/functions_*/.netlify/edge-functions/manifest.json !**/fixtures/**/monorepo/**/.netlify -!**/tests/deploy_config/fixtures/**/.netlify **/plugins/deno-cli lib diff --git a/packages/build/src/plugins_core/edge_functions/index.ts b/packages/build/src/plugins_core/edge_functions/index.ts index 07d4c9e1fe..f16b66bb8a 100644 --- a/packages/build/src/plugins_core/edge_functions/index.ts +++ b/packages/build/src/plugins_core/edge_functions/index.ts @@ -57,7 +57,7 @@ const coreStep = async function ({ if (featureFlags.netlify_build_frameworks_api) { if (await pathExists(frameworksAPISrcPath)) { - generatedFunctionPaths.unshift(frameworksAPISrcPath) + generatedFunctionPaths.push(frameworksAPISrcPath) } const frameworkImportMap = resolve( diff --git a/packages/build/src/plugins_core/deploy_config/index.ts b/packages/build/src/plugins_core/frameworks_api/index.ts similarity index 100% rename from packages/build/src/plugins_core/deploy_config/index.ts rename to packages/build/src/plugins_core/frameworks_api/index.ts diff --git a/packages/build/src/plugins_core/deploy_config/util.ts b/packages/build/src/plugins_core/frameworks_api/util.ts similarity index 100% rename from packages/build/src/plugins_core/deploy_config/util.ts rename to packages/build/src/plugins_core/frameworks_api/util.ts diff --git a/packages/build/src/plugins_core/functions/index.ts b/packages/build/src/plugins_core/functions/index.ts index da6e32bda5..29beaec90f 100644 --- a/packages/build/src/plugins_core/functions/index.ts +++ b/packages/build/src/plugins_core/functions/index.ts @@ -92,7 +92,7 @@ const zipFunctionsAndLogResults = async ({ // Printing an empty line before bundling output. log(logs, '') - const sourceDirectories = [frameworkFunctionsSrc, internalFunctionsSrc, functionsSrc].filter(Boolean) + const sourceDirectories = [internalFunctionsSrc, frameworkFunctionsSrc, functionsSrc].filter(Boolean) const results = await zipItAndShipIt.zipFunctions(sourceDirectories, functionsDist, zisiParameters) validateCustomRoutes(results) diff --git a/packages/build/src/plugins_core/pre_cleanup/index.ts b/packages/build/src/plugins_core/pre_cleanup/index.ts index e189b63128..3fa1035c7f 100644 --- a/packages/build/src/plugins_core/pre_cleanup/index.ts +++ b/packages/build/src/plugins_core/pre_cleanup/index.ts @@ -1,12 +1,15 @@ import { rm } from 'node:fs/promises' +import { resolve } from 'node:path' -import { scanForBlobs, getBlobsDirs } from '../../utils/blobs.js' -import { CoreStep, CoreStepCondition, CoreStepFunction } from '../types.js' +import { getBlobsDirs } from '../../utils/blobs.js' +import { FRAMEWORKS_API_ENDPOINT } from '../../utils/frameworks_api.js' +import { CoreStep, CoreStepFunction } from '../types.js' const coreStep: CoreStepFunction = async ({ buildDir, packagePath }) => { - const blobsDirs = getBlobsDirs(buildDir, packagePath) + const dirs = [...getBlobsDirs(buildDir, packagePath), resolve(buildDir, packagePath || '', FRAMEWORKS_API_ENDPOINT)] + try { - await Promise.all(blobsDirs.map((dir) => rm(dir, { recursive: true, force: true }))) + await Promise.all(dirs.map((dir) => rm(dir, { recursive: true, force: true }))) } catch { // Ignore errors if it fails, we can continue anyway. } @@ -14,15 +17,11 @@ const coreStep: CoreStepFunction = async ({ buildDir, packagePath }) => { return {} } -const blobsPresent: CoreStepCondition = async ({ buildDir, packagePath }) => - Boolean(await scanForBlobs(buildDir, packagePath)) - export const preCleanup: CoreStep = { event: 'onPreBuild', coreStep, coreStepId: 'pre_cleanup', coreStepName: 'Pre cleanup', coreStepDescription: () => 'Cleaning up leftover files from previous builds', - condition: blobsPresent, quiet: true, } diff --git a/packages/build/src/steps/get.ts b/packages/build/src/steps/get.ts index 449c265af1..00fb23acda 100644 --- a/packages/build/src/steps/get.ts +++ b/packages/build/src/steps/get.ts @@ -3,9 +3,9 @@ import { DEV_EVENTS, EVENTS } from '../plugins/events.js' import { uploadBlobs } from '../plugins_core/blobs_upload/index.js' import { buildCommandCore } from '../plugins_core/build_command.js' import { deploySite } from '../plugins_core/deploy/index.js' -import { applyDeployConfig } from '../plugins_core/deploy_config/index.js' import { devUploadBlobs } from '../plugins_core/dev_blobs_upload/index.js' import { bundleEdgeFunctions } from '../plugins_core/edge_functions/index.js' +import { applyDeployConfig } from '../plugins_core/frameworks_api/index.js' import { bundleFunctions } from '../plugins_core/functions/index.js' import { preCleanup } from '../plugins_core/pre_cleanup/index.js' import { preDevCleanup } from '../plugins_core/pre_dev_cleanup/index.js' diff --git a/packages/build/src/utils/blobs.ts b/packages/build/src/utils/blobs.ts index 56d41f2bf7..5b9a38f017 100644 --- a/packages/build/src/utils/blobs.ts +++ b/packages/build/src/utils/blobs.ts @@ -107,14 +107,13 @@ const METADATA_SUFFIX = '.json' * path to its metadata file. */ export const getKeysToUpload = async (blobsDir: string) => { - const blobsToUpload: { key: string; contentPath: string; metadataPath: string }[] = [] const files = await new fdir() .withRelativePaths() // we want the relative path from the blobsDir .filter((fpath) => !path.basename(fpath).startsWith(METADATA_PREFIX)) .crawl(blobsDir) .withPromise() - files.forEach((filePath) => { + return files.map((filePath) => { const key = filePath.split(path.sep).join('/') const contentPath = path.resolve(blobsDir, filePath) const basename = path.basename(filePath) @@ -124,14 +123,12 @@ export const getKeysToUpload = async (blobsDir: string) => { `${METADATA_PREFIX}${basename}${METADATA_SUFFIX}`, ) - blobsToUpload.push({ + return { key, contentPath, metadataPath, - }) + } }) - - return blobsToUpload } /** Read a file and its metadata file from the blobs directory */ diff --git a/packages/build/src/utils/frameworks_api.ts b/packages/build/src/utils/frameworks_api.ts index 359dc19a36..af930bc79a 100644 --- a/packages/build/src/utils/frameworks_api.ts +++ b/packages/build/src/utils/frameworks_api.ts @@ -2,11 +2,12 @@ import { basename, dirname, resolve, sep } from 'node:path' import { fdir } from 'fdir' -export const FRAMEWORKS_API_BLOBS_ENDPOINT = '.netlify/v1/blobs' -export const FRAMEWORKS_API_CONFIG_ENDPOINT = '.netlify/v1/config.json' -export const FRAMEWORKS_API_EDGE_FUNCTIONS_ENDPOINT = '.netlify/v1/edge-functions' +export const FRAMEWORKS_API_ENDPOINT = '.netlify/v1' +export const FRAMEWORKS_API_BLOBS_ENDPOINT = `${FRAMEWORKS_API_ENDPOINT}/blobs` +export const FRAMEWORKS_API_CONFIG_ENDPOINT = `${FRAMEWORKS_API_ENDPOINT}/config.json` +export const FRAMEWORKS_API_EDGE_FUNCTIONS_ENDPOINT = `${FRAMEWORKS_API_ENDPOINT}/edge-functions` export const FRAMEWORKS_API_EDGE_FUNCTIONS_IMPORT_MAP = 'import_map.json' -export const FRAMEWORKS_API_FUNCTIONS_ENDPOINT = '.netlify/v1/functions' +export const FRAMEWORKS_API_FUNCTIONS_ENDPOINT = `${FRAMEWORKS_API_ENDPOINT}/functions` type DirectoryTreeFiles = Map diff --git a/packages/build/tests/core/snapshots/tests.js.md b/packages/build/tests/core/snapshots/tests.js.md index 78099c9480..d20b902558 100644 --- a/packages/build/tests/core/snapshots/tests.js.md +++ b/packages/build/tests/core/snapshots/tests.js.md @@ -917,9 +917,9 @@ Generated by [AVA](https://avajs.dev). ␊ Running \`netlify build\` will execute this build flow␊ ␊ - ┌──────────────┬──────────────┐␊ - │ Event │ Location │␊ - └──────────────┴──────────────┘␊ + ┌─────────────────┬─────────────────┐␊ + │ Event │ Location │␊ + └─────────────────┴─────────────────┘␊ ␊ If this looks good to you, run \`netlify build\` to execute the build␊ ` @@ -1026,9 +1026,9 @@ Generated by [AVA](https://avajs.dev). ␊ Running \`netlify build\` will execute this build flow␊ ␊ - ┌──────────────┬──────────────┐␊ - │ Event │ Location │␊ - └──────────────┴──────────────┘␊ + ┌─────────────────┬─────────────────┐␊ + │ Event │ Location │␊ + └─────────────────┴─────────────────┘␊ ␊ If this looks good to you, run \`netlify build\` to execute the build␊ ` @@ -1073,12 +1073,12 @@ Generated by [AVA](https://avajs.dev). ␊ Running \`netlify build\` will execute this build flow␊ ␊ - ┌──────────────┬──────────────┐␊ - │ Event │ Location │␊ - └──────────────┴──────────────┘␊ - ┌──────────────┐␊ - │ 1. onBuild ↓ │ Build command from Netlify app␊ - └──────────────┘ ␊ + ┌─────────────────┬─────────────────┐␊ + │ Event │ Location │␊ + └─────────────────┴─────────────────┘␊ + ┌─────────────────┐␊ + │ 1. onBuild ↓ │ Build command from Netlify app␊ + └─────────────────┘ ␊ ␊ If this looks good to you, run \`netlify build\` to execute the build␊ ` diff --git a/packages/build/tests/core/snapshots/tests.js.snap b/packages/build/tests/core/snapshots/tests.js.snap index 5c41b8c447..1dc9bdf575 100644 Binary files a/packages/build/tests/core/snapshots/tests.js.snap and b/packages/build/tests/core/snapshots/tests.js.snap differ diff --git a/packages/build/tests/deploy_config/fixtures/from_build_command_legacy/.netlify/deploy/v1/config.json b/packages/build/tests/deploy_config/fixtures/from_build_command_legacy/.netlify/deploy/v1/config.json deleted file mode 100644 index 4d0822ca50..0000000000 --- a/packages/build/tests/deploy_config/fixtures/from_build_command_legacy/.netlify/deploy/v1/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "images": { - "remote_images": ["domain1.from-api.netlify", "domain2.from-api.netlify"] - } -} \ No newline at end of file diff --git a/packages/build/tests/deploy_config/fixtures/malformed_config/.netlify/v1/config.json b/packages/build/tests/deploy_config/fixtures/malformed_config/.netlify/v1/config.json deleted file mode 100644 index a696bd254e..0000000000 --- a/packages/build/tests/deploy_config/fixtures/malformed_config/.netlify/v1/config.json +++ /dev/null @@ -1 +0,0 @@ -not json \ No newline at end of file diff --git a/packages/build/tests/deploy_config/fixtures/with_build_plugin/.netlify/v1/config.json b/packages/build/tests/deploy_config/fixtures/with_build_plugin/.netlify/v1/config.json deleted file mode 100644 index 4d0822ca50..0000000000 --- a/packages/build/tests/deploy_config/fixtures/with_build_plugin/.netlify/v1/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "images": { - "remote_images": ["domain1.from-api.netlify", "domain2.from-api.netlify"] - } -} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_framework/build.mjs b/packages/build/tests/edge_functions/fixtures/functions_user_framework/build.mjs new file mode 100644 index 0000000000..e54abdc19b --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_framework/build.mjs @@ -0,0 +1,4 @@ +import { cp } from 'node:fs/promises' +import { resolve } from "node:path" + +await cp(resolve("frameworks_api_seed"), resolve(".netlify/v1"), { recursive: true }) diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/function-2.ts b/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/function-2.ts new file mode 100644 index 0000000000..4a1c73d5e3 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/function-2.ts @@ -0,0 +1,9 @@ +import { greeting } from "greeting" + +export default async () => new Response(greeting) + +export const config = { + excludedPath: "/framework/skip_*", + generator: "Hello", + path: "/framework/*" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/import_map.json b/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/import_map.json new file mode 100644 index 0000000000..fab8ef3da9 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/import_map.json @@ -0,0 +1,5 @@ +{ + "imports": { + "greeting": "./util/greeting.ts" + } +} diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/util/greeting.ts b/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/util/greeting.ts new file mode 100644 index 0000000000..ca9b5b1dec --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_framework/frameworks_api_seed/edge-functions/util/greeting.ts @@ -0,0 +1 @@ +export const greeting = "Hello world" diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_framework/netlify.toml b/packages/build/tests/edge_functions/fixtures/functions_user_framework/netlify.toml new file mode 100644 index 0000000000..3b2b6da08b --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_framework/netlify.toml @@ -0,0 +1,2 @@ +[build] +command = "node build.mjs" diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/edge-functions/frameworks-internal-conflict.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/edge-functions/frameworks-internal-conflict.ts new file mode 100644 index 0000000000..84ccb97f0c --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/edge-functions/frameworks-internal-conflict.ts @@ -0,0 +1,5 @@ +export default async () => new Response("Generated in the legacy internal directory") + +export const config = { + path: "/frameworks-internal-conflict/internal" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/v1/edge-functions/frameworks-internal-conflict.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/v1/edge-functions/frameworks-internal-conflict.ts new file mode 100644 index 0000000000..6dfb221224 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/v1/edge-functions/frameworks-internal-conflict.ts @@ -0,0 +1,5 @@ +export default async () => new Response("Generated by the Frameworks API") + +export const config = { + path: "/frameworks-internal-conflict/frameworks" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/v1/edge-functions/frameworks-user-conflict.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/v1/edge-functions/frameworks-user-conflict.ts new file mode 100644 index 0000000000..c3a2433ece --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/.netlify/v1/edge-functions/frameworks-user-conflict.ts @@ -0,0 +1,5 @@ +export default async () => new Response("Generated by the Frameworks API") + +export const config = { + path: "/frameworks-user-conflict/frameworks" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/build.mjs b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/build.mjs new file mode 100644 index 0000000000..e54abdc19b --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/build.mjs @@ -0,0 +1,4 @@ +import { cp } from 'node:fs/promises' +import { resolve } from "node:path" + +await cp(resolve("frameworks_api_seed"), resolve(".netlify/v1"), { recursive: true }) diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/frameworks-internal-conflict.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/frameworks-internal-conflict.ts new file mode 100644 index 0000000000..6dfb221224 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/frameworks-internal-conflict.ts @@ -0,0 +1,5 @@ +export default async () => new Response("Generated by the Frameworks API") + +export const config = { + path: "/frameworks-internal-conflict/frameworks" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/frameworks-user-conflict.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/frameworks-user-conflict.ts new file mode 100644 index 0000000000..c3a2433ece --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/frameworks-user-conflict.ts @@ -0,0 +1,5 @@ +export default async () => new Response("Generated by the Frameworks API") + +export const config = { + path: "/frameworks-user-conflict/frameworks" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/function-2.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/function-2.ts new file mode 100644 index 0000000000..4a1c73d5e3 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/function-2.ts @@ -0,0 +1,9 @@ +import { greeting } from "greeting" + +export default async () => new Response(greeting) + +export const config = { + excludedPath: "/framework/skip_*", + generator: "Hello", + path: "/framework/*" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/import_map.json b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/import_map.json new file mode 100644 index 0000000000..fab8ef3da9 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/import_map.json @@ -0,0 +1,5 @@ +{ + "imports": { + "greeting": "./util/greeting.ts" + } +} diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/util/greeting.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/util/greeting.ts new file mode 100644 index 0000000000..ca9b5b1dec --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/frameworks_api_seed/edge-functions/util/greeting.ts @@ -0,0 +1 @@ +export const greeting = "Hello world" diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify.toml b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify.toml new file mode 100644 index 0000000000..3b2b6da08b --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify.toml @@ -0,0 +1,2 @@ +[build] +command = "node build.mjs" diff --git a/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify/edge-functions/frameworks-user-conflict.ts b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify/edge-functions/frameworks-user-conflict.ts new file mode 100644 index 0000000000..259e955a71 --- /dev/null +++ b/packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify/edge-functions/frameworks-user-conflict.ts @@ -0,0 +1,5 @@ +export default async () => new Response("Generated by the user") + +export const config = { + path: "/frameworks-user-conflict/user" +} \ No newline at end of file diff --git a/packages/build/tests/edge_functions/snapshots/tests.js.md b/packages/build/tests/edge_functions/snapshots/tests.js.md index 4668fb3654..aa9ec76981 100644 --- a/packages/build/tests/edge_functions/snapshots/tests.js.md +++ b/packages/build/tests/edge_functions/snapshots/tests.js.md @@ -767,11 +767,18 @@ Generated by [AVA](https://avajs.dev). packages/build/tests/edge_functions/fixtures/functions_user_framework␊ ␊ > Config file␊ - No config file was defined: using default values.␊ + packages/build/tests/edge_functions/fixtures/functions_user_framework/netlify.toml␊ ␊ > Context␊ production␊ ␊ + build.command from netlify.toml ␊ + ────────────────────────────────────────────────────────────────␊ + ␊ + $ node build.mjs␊ + ␊ + (build.command completed in 1ms)␊ + ␊ Edge Functions bundling ␊ ────────────────────────────────────────────────────────────────␊ ␊ @@ -806,21 +813,32 @@ Generated by [AVA](https://avajs.dev). packages/build/tests/edge_functions/fixtures/functions_user_internal_framework␊ ␊ > Config file␊ - No config file was defined: using default values.␊ + packages/build/tests/edge_functions/fixtures/functions_user_internal_framework/netlify.toml␊ ␊ > Context␊ production␊ ␊ + build.command from netlify.toml ␊ + ────────────────────────────────────────────────────────────────␊ + ␊ + $ node build.mjs␊ + ␊ + (build.command completed in 1ms)␊ + ␊ Edge Functions bundling ␊ ────────────────────────────────────────────────────────────────␊ ␊ Packaging Edge Functions from .netlify/edge-functions directory:␊ + - frameworks-internal-conflict␊ - function-3␊ ␊ Packaging Edge Functions generated by your framework:␊ + - frameworks-internal-conflict␊ + - frameworks-user-conflict␊ - function-2␊ ␊ Packaging Edge Functions from netlify/edge-functions directory:␊ + - frameworks-user-conflict␊ - function-1␊ ␊ (Edge Functions bundling completed in 1ms)␊ diff --git a/packages/build/tests/edge_functions/snapshots/tests.js.snap b/packages/build/tests/edge_functions/snapshots/tests.js.snap index 7f803ae5dc..aa10641e5c 100644 Binary files a/packages/build/tests/edge_functions/snapshots/tests.js.snap and b/packages/build/tests/edge_functions/snapshots/tests.js.snap differ diff --git a/packages/build/tests/edge_functions/tests.js b/packages/build/tests/edge_functions/tests.js index 69a411ee1d..4a374b09ef 100644 --- a/packages/build/tests/edge_functions/tests.js +++ b/packages/build/tests/edge_functions/tests.js @@ -1,11 +1,12 @@ import { promises as fs } from 'fs' import { join } from 'path' -import { platform } from 'process' +import { platform, version as nodeVersion } from 'process' import { fileURLToPath } from 'url' import { Fixture, normalizeOutput } from '@netlify/testing' import test from 'ava' import { pathExists } from 'path-exists' +import semver from 'semver' import tmp from 'tmp-promise' import { importJsonFile } from '../../lib/utils/json.js' @@ -214,32 +215,10 @@ test.serial('cleans up the edge functions dist directory before bundling', async t.false(await pathExists(oldBundlePath)) }) -test.serial('builds edge functions generated with the Frameworks API', async (t) => { - const output = await new Fixture('./fixtures/functions_user_framework') - .withFlags({ - debug: false, - featureFlags: { netlify_build_frameworks_api: true }, - mode: 'buildbot', - }) - .runWithBuild() - - t.snapshot(normalizeOutput(output)) - - const { routes } = await assertManifest(t, 'functions_user_framework') - - t.is(routes.length, 1) - t.deepEqual(routes[0], { - function: 'function-2', - pattern: '^/framework(?:/(.*))/?$', - excluded_patterns: ['^/framework/skip_(.*)/?$'], - path: '/framework/*', - }) -}) - -test.serial( - 'builds both edge functions generated with the Frameworks API and the ones in the internal directory', - async (t) => { - const output = await new Fixture('./fixtures/functions_user_internal_framework') +// Targeting Node 16.7.0+ because these fixtures rely on `fs.cp()`. +if (semver.gte(nodeVersion, '16.7.0')) { + test.serial('builds edge functions generated with the Frameworks API', async (t) => { + const output = await new Fixture('./fixtures/functions_user_framework') .withFlags({ debug: false, featureFlags: { netlify_build_frameworks_api: true }, @@ -249,26 +228,70 @@ test.serial( t.snapshot(normalizeOutput(output)) - const { routes } = await assertManifest(t, 'functions_user_internal_framework') + const { routes } = await assertManifest(t, 'functions_user_framework') - t.is(routes.length, 3) + t.is(routes.length, 1) t.deepEqual(routes[0], { function: 'function-2', pattern: '^/framework(?:/(.*))/?$', excluded_patterns: ['^/framework/skip_(.*)/?$'], path: '/framework/*', }) - t.deepEqual(routes[1], { - function: 'function-3', - pattern: '^/internal(?:/(.*))/?$', - excluded_patterns: ['^/internal/skip_(.*)/?$'], - path: '/internal/*', - }) - t.deepEqual(routes[2], { - function: 'function-1', - pattern: '^/user/?$', - excluded_patterns: [], - path: '/user', - }) - }, -) + }) + + test.serial( + 'builds both edge functions generated with the Frameworks API and the ones in the internal directory', + async (t) => { + const output = await new Fixture('./fixtures/functions_user_internal_framework') + .withFlags({ + debug: false, + featureFlags: { netlify_build_frameworks_api: true }, + mode: 'buildbot', + }) + .runWithBuild() + + t.snapshot(normalizeOutput(output)) + + const { routes } = await assertManifest(t, 'functions_user_internal_framework') + + t.deepEqual(routes, [ + { + function: 'frameworks-internal-conflict', + pattern: '^/frameworks-internal-conflict/frameworks/?$', + excluded_patterns: [], + path: '/frameworks-internal-conflict/frameworks', + }, + { + function: 'function-3', + pattern: '^/internal(?:/(.*))/?$', + excluded_patterns: ['^/internal/skip_(.*)/?$'], + path: '/internal/*', + }, + { + function: 'frameworks-user-conflict', + pattern: '^/frameworks-user-conflict/frameworks/?$', + excluded_patterns: [], + path: '/frameworks-user-conflict/frameworks', + }, + { + function: 'function-2', + pattern: '^/framework(?:/(.*))/?$', + excluded_patterns: ['^/framework/skip_(.*)/?$'], + path: '/framework/*', + }, + { + function: 'frameworks-user-conflict', + pattern: '^/frameworks-user-conflict/user/?$', + excluded_patterns: [], + path: '/frameworks-user-conflict/user', + }, + { + function: 'function-1', + pattern: '^/user/?$', + excluded_patterns: [], + path: '/user', + }, + ]) + }, + ) +} diff --git a/packages/build/tests/deploy_config/fixtures/from_build_command/.netlify/v1/config.json b/packages/build/tests/frameworks_api/fixtures/from_build_command/build.mjs similarity index 71% rename from packages/build/tests/deploy_config/fixtures/from_build_command/.netlify/v1/config.json rename to packages/build/tests/frameworks_api/fixtures/from_build_command/build.mjs index b6ab42ceb0..5382eab231 100644 --- a/packages/build/tests/deploy_config/fixtures/from_build_command/.netlify/v1/config.json +++ b/packages/build/tests/frameworks_api/fixtures/from_build_command/build.mjs @@ -1,4 +1,6 @@ -{ +import { mkdir, writeFile } from 'node:fs/promises' + +const config = { "functions": { "my_framework*": { "included_files": ["files/**"] @@ -23,4 +25,8 @@ "images": { "remote_images": ["domain1.from-api.netlify", "domain2.from-api.netlify"] } -} \ No newline at end of file +} + +await mkdir('.netlify/v1', { recursive: true }) + +await writeFile('.netlify/v1/config.json', JSON.stringify(config)) \ No newline at end of file diff --git a/packages/build/tests/deploy_config/fixtures/from_build_command_legacy/netlify.toml b/packages/build/tests/frameworks_api/fixtures/from_build_command/netlify.toml similarity index 70% rename from packages/build/tests/deploy_config/fixtures/from_build_command_legacy/netlify.toml rename to packages/build/tests/frameworks_api/fixtures/from_build_command/netlify.toml index f2da736324..e557386c07 100644 --- a/packages/build/tests/deploy_config/fixtures/from_build_command_legacy/netlify.toml +++ b/packages/build/tests/frameworks_api/fixtures/from_build_command/netlify.toml @@ -1,2 +1,5 @@ +[build] +command = "node build.mjs" + [images] remote_images = ["domain1.from-toml.netlify", "domain2.from-toml.netlify"] diff --git a/packages/build/tests/frameworks_api/fixtures/from_build_command_legacy/build.mjs b/packages/build/tests/frameworks_api/fixtures/from_build_command_legacy/build.mjs new file mode 100644 index 0000000000..c6b12f7fd1 --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/from_build_command_legacy/build.mjs @@ -0,0 +1,11 @@ +import { mkdir, writeFile } from 'node:fs/promises' + +const config = { + "images": { + "remote_images": ["domain1.from-api.netlify", "domain2.from-api.netlify"] + } +} + +await mkdir('.netlify/v1', { recursive: true }) + +await writeFile('.netlify/v1/config.json', JSON.stringify(config)) \ No newline at end of file diff --git a/packages/build/tests/frameworks_api/fixtures/from_build_command_legacy/netlify.toml b/packages/build/tests/frameworks_api/fixtures/from_build_command_legacy/netlify.toml new file mode 100644 index 0000000000..e557386c07 --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/from_build_command_legacy/netlify.toml @@ -0,0 +1,5 @@ +[build] +command = "node build.mjs" + +[images] +remote_images = ["domain1.from-toml.netlify", "domain2.from-toml.netlify"] diff --git a/packages/build/tests/deploy_config/fixtures/readonly_properties/.netlify/v1/config.json b/packages/build/tests/frameworks_api/fixtures/leftover_config/config.seed.json similarity index 51% rename from packages/build/tests/deploy_config/fixtures/readonly_properties/.netlify/v1/config.json rename to packages/build/tests/frameworks_api/fixtures/leftover_config/config.seed.json index 81a2292085..a9a0421ba9 100644 --- a/packages/build/tests/deploy_config/fixtures/readonly_properties/.netlify/v1/config.json +++ b/packages/build/tests/frameworks_api/fixtures/leftover_config/config.seed.json @@ -1,9 +1,4 @@ { - "plugins": [ - { - "package": "@netlify/imaginary-plugin" - } - ], "images": { "remote_images": ["domain1.netlify", "domain2.netlify"] } diff --git a/packages/build/tests/deploy_config/fixtures/from_build_command/netlify.toml b/packages/build/tests/frameworks_api/fixtures/leftover_config/netlify.toml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/from_build_command/netlify.toml rename to packages/build/tests/frameworks_api/fixtures/leftover_config/netlify.toml diff --git a/packages/build/tests/frameworks_api/fixtures/malformed_config/build.mjs b/packages/build/tests/frameworks_api/fixtures/malformed_config/build.mjs new file mode 100644 index 0000000000..d6c870bf94 --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/malformed_config/build.mjs @@ -0,0 +1,5 @@ +import { mkdir, writeFile } from 'node:fs/promises' + +await mkdir('.netlify/v1', { recursive: true }) + +await writeFile('.netlify/v1/config.json', "not json") \ No newline at end of file diff --git a/packages/build/tests/frameworks_api/fixtures/malformed_config/netlify.toml b/packages/build/tests/frameworks_api/fixtures/malformed_config/netlify.toml new file mode 100644 index 0000000000..3b2b6da08b --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/malformed_config/netlify.toml @@ -0,0 +1,2 @@ +[build] +command = "node build.mjs" diff --git a/packages/build/tests/deploy_config/fixtures/missing_config/manifest.yml b/packages/build/tests/frameworks_api/fixtures/missing_config/manifest.yml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/missing_config/manifest.yml rename to packages/build/tests/frameworks_api/fixtures/missing_config/manifest.yml diff --git a/packages/build/tests/deploy_config/fixtures/missing_config/netlify.toml b/packages/build/tests/frameworks_api/fixtures/missing_config/netlify.toml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/missing_config/netlify.toml rename to packages/build/tests/frameworks_api/fixtures/missing_config/netlify.toml diff --git a/packages/build/tests/deploy_config/fixtures/missing_config/plugin.js b/packages/build/tests/frameworks_api/fixtures/missing_config/plugin.js similarity index 100% rename from packages/build/tests/deploy_config/fixtures/missing_config/plugin.js rename to packages/build/tests/frameworks_api/fixtures/missing_config/plugin.js diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/apps/app-1/build.mjs b/packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-1/build.mjs similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/apps/app-1/build.mjs rename to packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-1/build.mjs diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/apps/app-1/netlify.toml b/packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-1/netlify.toml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/apps/app-1/netlify.toml rename to packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-1/netlify.toml diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/apps/app-1/package.json b/packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-1/package.json similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/apps/app-1/package.json rename to packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-1/package.json diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/apps/app-2/build.mjs b/packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-2/build.mjs similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/apps/app-2/build.mjs rename to packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-2/build.mjs diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/apps/app-2/netlify.toml b/packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-2/netlify.toml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/apps/app-2/netlify.toml rename to packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-2/netlify.toml diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/apps/app-2/package.json b/packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-2/package.json similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/apps/app-2/package.json rename to packages/build/tests/frameworks_api/fixtures/monorepo/apps/app-2/package.json diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/package.json b/packages/build/tests/frameworks_api/fixtures/monorepo/package.json similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/package.json rename to packages/build/tests/frameworks_api/fixtures/monorepo/package.json diff --git a/packages/build/tests/deploy_config/fixtures/monorepo/pnpm-workspace.yaml b/packages/build/tests/frameworks_api/fixtures/monorepo/pnpm-workspace.yaml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/monorepo/pnpm-workspace.yaml rename to packages/build/tests/frameworks_api/fixtures/monorepo/pnpm-workspace.yaml diff --git a/packages/build/tests/frameworks_api/fixtures/readonly_properties/build.mjs b/packages/build/tests/frameworks_api/fixtures/readonly_properties/build.mjs new file mode 100644 index 0000000000..db187dbe84 --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/readonly_properties/build.mjs @@ -0,0 +1,16 @@ +import { mkdir, writeFile } from 'node:fs/promises' + +const config = { + "plugins": [ + { + "package": "@netlify/imaginary-plugin" + } + ], + "images": { + "remote_images": ["domain1.netlify", "domain2.netlify"] + } +} + +await mkdir('.netlify/v1', { recursive: true }) + +await writeFile('.netlify/v1/config.json', JSON.stringify(config)) \ No newline at end of file diff --git a/packages/build/tests/frameworks_api/fixtures/readonly_properties/netlify.toml b/packages/build/tests/frameworks_api/fixtures/readonly_properties/netlify.toml new file mode 100644 index 0000000000..3b2b6da08b --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/readonly_properties/netlify.toml @@ -0,0 +1,2 @@ +[build] +command = "node build.mjs" diff --git a/packages/build/tests/frameworks_api/fixtures/with_build_plugin/build.mjs b/packages/build/tests/frameworks_api/fixtures/with_build_plugin/build.mjs new file mode 100644 index 0000000000..c6b12f7fd1 --- /dev/null +++ b/packages/build/tests/frameworks_api/fixtures/with_build_plugin/build.mjs @@ -0,0 +1,11 @@ +import { mkdir, writeFile } from 'node:fs/promises' + +const config = { + "images": { + "remote_images": ["domain1.from-api.netlify", "domain2.from-api.netlify"] + } +} + +await mkdir('.netlify/v1', { recursive: true }) + +await writeFile('.netlify/v1/config.json', JSON.stringify(config)) \ No newline at end of file diff --git a/packages/build/tests/deploy_config/fixtures/with_build_plugin/manifest.yml b/packages/build/tests/frameworks_api/fixtures/with_build_plugin/manifest.yml similarity index 100% rename from packages/build/tests/deploy_config/fixtures/with_build_plugin/manifest.yml rename to packages/build/tests/frameworks_api/fixtures/with_build_plugin/manifest.yml diff --git a/packages/build/tests/deploy_config/fixtures/with_build_plugin/netlify.toml b/packages/build/tests/frameworks_api/fixtures/with_build_plugin/netlify.toml similarity index 50% rename from packages/build/tests/deploy_config/fixtures/with_build_plugin/netlify.toml rename to packages/build/tests/frameworks_api/fixtures/with_build_plugin/netlify.toml index 4b06556c85..8f65f19109 100644 --- a/packages/build/tests/deploy_config/fixtures/with_build_plugin/netlify.toml +++ b/packages/build/tests/frameworks_api/fixtures/with_build_plugin/netlify.toml @@ -1,2 +1,5 @@ +[build] +command = "node build.mjs" + [[plugins]] package = "./plugin.js" diff --git a/packages/build/tests/deploy_config/fixtures/with_build_plugin/plugin.js b/packages/build/tests/frameworks_api/fixtures/with_build_plugin/plugin.js similarity index 100% rename from packages/build/tests/deploy_config/fixtures/with_build_plugin/plugin.js rename to packages/build/tests/frameworks_api/fixtures/with_build_plugin/plugin.js diff --git a/packages/build/tests/deploy_config/tests.js b/packages/build/tests/frameworks_api/tests.js similarity index 85% rename from packages/build/tests/deploy_config/tests.js rename to packages/build/tests/frameworks_api/tests.js index 9b7bc2e59c..36d4e9e623 100644 --- a/packages/build/tests/deploy_config/tests.js +++ b/packages/build/tests/frameworks_api/tests.js @@ -1,4 +1,5 @@ import { promises as fs } from 'fs' +import { dirname, resolve } from 'path' import { platform, version as nodeVersion } from 'process' import { Fixture } from '@netlify/testing' @@ -132,3 +133,21 @@ test('Does not throw an error if the deploy configuration file is missing', asyn const { success } = await new Fixture('./fixtures/missing_config').runWithBuildAndIntrospect() t.true(success) }) + +test('Removes any leftover files from a previous build', async (t) => { + const systemLogFile = await tmp.file() + const fixture = new Fixture('./fixtures/leftover_config').withFlags({ + debug: false, + systemLogFile: systemLogFile.fd, + }) + const configPath = resolve(fixture.repositoryRoot, '.netlify/v1/config.json') + + await fs.mkdir(dirname(configPath), { force: true, recursive: true }) + await fs.copyFile(resolve(fixture.repositoryRoot, 'config.seed.json'), configPath) + + const { netlifyConfig } = await fixture.runWithBuildAndIntrospect() + + t.deepEqual(netlifyConfig.images, { + remote_images: ['domain1.from-toml.netlify', 'domain2.from-toml.netlify'], + }) +}) diff --git a/packages/build/tests/functions/fixtures/functions_user_and_frameworks/build.mjs b/packages/build/tests/functions/fixtures/functions_user_and_frameworks/build.mjs new file mode 100644 index 0000000000..e54abdc19b --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_and_frameworks/build.mjs @@ -0,0 +1,4 @@ +import { cp } from 'node:fs/promises' +import { resolve } from "node:path" + +await cp(resolve("frameworks_api_seed"), resolve(".netlify/v1"), { recursive: true }) diff --git a/packages/build/tests/functions/fixtures/functions_user_and_frameworks/.netlify/v1/functions/server.mjs b/packages/build/tests/functions/fixtures/functions_user_and_frameworks/frameworks_api_seed/functions/server.mjs similarity index 100% rename from packages/build/tests/functions/fixtures/functions_user_and_frameworks/.netlify/v1/functions/server.mjs rename to packages/build/tests/functions/fixtures/functions_user_and_frameworks/frameworks_api_seed/functions/server.mjs diff --git a/packages/build/tests/functions/fixtures/functions_user_and_frameworks/netlify.toml b/packages/build/tests/functions/fixtures/functions_user_and_frameworks/netlify.toml new file mode 100644 index 0000000000..3b2b6da08b --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_and_frameworks/netlify.toml @@ -0,0 +1,2 @@ +[build] +command = "node build.mjs" diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/.netlify/functions-internal/frameworks-internal-conflict.mjs b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/.netlify/functions-internal/frameworks-internal-conflict.mjs new file mode 100644 index 0000000000..adf55f3b27 --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/.netlify/functions-internal/frameworks-internal-conflict.mjs @@ -0,0 +1,5 @@ +export default () => new Response("Generated in the internal functions directory") + +export const config = { + path: "/frameworks-internal-conflict/internal" +} diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/build.mjs b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/build.mjs new file mode 100644 index 0000000000..e54abdc19b --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/build.mjs @@ -0,0 +1,4 @@ +import { cp } from 'node:fs/promises' +import { resolve } from "node:path" + +await cp(resolve("frameworks_api_seed"), resolve(".netlify/v1"), { recursive: true }) diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/frameworks-internal-conflict.mjs b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/frameworks-internal-conflict.mjs new file mode 100644 index 0000000000..98a53b482e --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/frameworks-internal-conflict.mjs @@ -0,0 +1,5 @@ +export default () => new Response("Generated by the Frameworks API") + +export const config = { + path: "/frameworks-internal-conflict/frameworks" +} diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/frameworks-user-conflict.mjs b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/frameworks-user-conflict.mjs new file mode 100644 index 0000000000..dbb1c35842 --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/frameworks-user-conflict.mjs @@ -0,0 +1,5 @@ +export default () => new Response("Generated by the Frameworks API") + +export const config = { + path: "/frameworks-user-conflict/frameworks" +} diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/.netlify/v1/functions/server.mjs b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/server.mjs similarity index 100% rename from packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/.netlify/v1/functions/server.mjs rename to packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/frameworks_api_seed/functions/server.mjs diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/netlify.toml b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/netlify.toml new file mode 100644 index 0000000000..3b2b6da08b --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/netlify.toml @@ -0,0 +1,2 @@ +[build] +command = "node build.mjs" diff --git a/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/netlify/functions/frameworks-user-conflict.mjs b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/netlify/functions/frameworks-user-conflict.mjs new file mode 100644 index 0000000000..c7a1ce3489 --- /dev/null +++ b/packages/build/tests/functions/fixtures/functions_user_internal_and_frameworks/netlify/functions/frameworks-user-conflict.mjs @@ -0,0 +1,5 @@ +export default () => new Response("Generated by the user") + +export const config = { + path: "/frameworks-user-conflict/user" +} diff --git a/packages/build/tests/functions/snapshots/tests.js.md b/packages/build/tests/functions/snapshots/tests.js.md index 6685e0abbd..f21e4dcb1f 100644 --- a/packages/build/tests/functions/snapshots/tests.js.md +++ b/packages/build/tests/functions/snapshots/tests.js.md @@ -352,11 +352,18 @@ Generated by [AVA](https://avajs.dev). /tmp-dir␊ ␊ > Config file␊ - No config file was defined: using default values.␊ + /tmp-dir/netlify.toml␊ ␊ > Context␊ production␊ ␊ + build.command from netlify.toml ␊ + ────────────────────────────────────────────────────────────────␊ + ␊ + $ node build.mjs␊ + ␊ + (build.command completed in 1ms)␊ + ␊ Functions bundling ␊ ────────────────────────────────────────────────────────────────␊ ␊ @@ -382,7 +389,7 @@ Generated by [AVA](https://avajs.dev). ␊ (Netlify Build completed in 1ms)` -## Functions: legacy `.netlify/functions-internal` directory is ignored if there are functions generated with the Frameworks API +## Functions: loads functions from the `.netlify/functions-internal` directory and the Frameworks API > Snapshot 1 @@ -400,21 +407,32 @@ Generated by [AVA](https://avajs.dev). /tmp-dir␊ ␊ > Config file␊ - No config file was defined: using default values.␊ + /tmp-dir/netlify.toml␊ ␊ > Context␊ production␊ ␊ + build.command from netlify.toml ␊ + ────────────────────────────────────────────────────────────────␊ + ␊ + $ node build.mjs␊ + ␊ + (build.command completed in 1ms)␊ + ␊ Functions bundling ␊ ────────────────────────────────────────────────────────────────␊ ␊ Packaging Functions from .netlify/functions-internal directory:␊ + - frameworks-internal-conflict.mjs␊ - server-internal.mjs␊ ␊ Packaging Functions generated by your framework:␊ + - frameworks-internal-conflict.mjs␊ + - frameworks-user-conflict.mjs␊ - server.mjs␊ ␊ Packaging Functions from netlify/functions directory:␊ + - frameworks-user-conflict.mjs␊ - user.ts␊ ␊ ␊ diff --git a/packages/build/tests/functions/snapshots/tests.js.snap b/packages/build/tests/functions/snapshots/tests.js.snap index 172e19a1d8..0c3cf65696 100644 Binary files a/packages/build/tests/functions/snapshots/tests.js.snap and b/packages/build/tests/functions/snapshots/tests.js.snap differ diff --git a/packages/build/tests/functions/tests.js b/packages/build/tests/functions/tests.js index 02fda63dac..3d7d505bf9 100644 --- a/packages/build/tests/functions/tests.js +++ b/packages/build/tests/functions/tests.js @@ -1,4 +1,4 @@ -import { readdir, rm, stat, writeFile } from 'fs/promises' +import { readdir, readFile, rm, stat, writeFile } from 'fs/promises' import { resolve } from 'path' import { version as nodeVersion } from 'process' import { fileURLToPath } from 'url' @@ -121,36 +121,52 @@ test('Functions: cleanup is only triggered when there are internal functions', a t.false(output.includes('Cleaning up leftover files from previous builds')) }) -test('Functions: loads functions generated with the Frameworks API', async (t) => { - const fixture = await new Fixture('./fixtures/functions_user_and_frameworks') - .withFlags({ debug: false, featureFlags: { netlify_build_frameworks_api: true } }) - .withCopyRoot() +// Targeting Node 16.7.0+ because these fixtures rely on `fs.cp()`. +if (semver.gte(nodeVersion, '16.7.0')) { + test('Functions: loads functions generated with the Frameworks API', async (t) => { + const fixture = await new Fixture('./fixtures/functions_user_and_frameworks') + .withFlags({ debug: false, featureFlags: { netlify_build_frameworks_api: true } }) + .withCopyRoot() - const output = await fixture.runWithBuild() - const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) + const output = await fixture.runWithBuild() + const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) - t.true(functionsDist.includes('manifest.json')) - t.true(functionsDist.includes('server.zip')) - t.true(functionsDist.includes('user.zip')) + t.true(functionsDist.includes('manifest.json')) + t.true(functionsDist.includes('server.zip')) + t.true(functionsDist.includes('user.zip')) - t.snapshot(normalizeOutput(output)) -}) + t.snapshot(normalizeOutput(output)) + }) -test('Functions: legacy `.netlify/functions-internal` directory is ignored if there are functions generated with the Frameworks API', async (t) => { - const fixture = await new Fixture('./fixtures/functions_user_internal_and_frameworks') - .withFlags({ debug: false, featureFlags: { netlify_build_frameworks_api: true } }) - .withCopyRoot() + test('Functions: loads functions from the `.netlify/functions-internal` directory and the Frameworks API', async (t) => { + const fixture = await new Fixture('./fixtures/functions_user_internal_and_frameworks') + .withFlags({ debug: false, featureFlags: { netlify_build_frameworks_api: true } }) + .withCopyRoot() - const output = await fixture.runWithBuild() - const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) + const output = await fixture.runWithBuild() + const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) - t.true(functionsDist.includes('manifest.json')) - t.true(functionsDist.includes('server.zip')) - t.true(functionsDist.includes('user.zip')) - t.true(functionsDist.includes('server-internal.zip')) + t.true(functionsDist.includes('manifest.json')) + t.true(functionsDist.includes('server.zip')) + t.true(functionsDist.includes('user.zip')) + t.true(functionsDist.includes('server-internal.zip')) - t.snapshot(normalizeOutput(output)) -}) + const manifest = await readFile(resolve(fixture.repositoryRoot, '.netlify/functions/manifest.json'), 'utf8') + const { functions } = JSON.parse(manifest) + + t.is(functions.length, 5) + + // The Frameworks API takes precedence over the legacy internal directory. + const frameworksInternalConflict = functions.find(({ name }) => name === 'frameworks-internal-conflict') + t.is(frameworksInternalConflict.routes[0].pattern, '/frameworks-internal-conflict/frameworks') + + // User code takes precedence over the Frameworks API. + const frameworksUserConflict = functions.find(({ name }) => name === 'frameworks-user-conflict') + t.is(frameworksUserConflict.routes[0].pattern, '/frameworks-user-conflict/user') + + t.snapshot(normalizeOutput(output)) + }) +} // pnpm is not available in Node 14. if (semver.gte(nodeVersion, '16.9.0')) { diff --git a/packages/build/tests/telemetry/snapshots/tests.js.md b/packages/build/tests/telemetry/snapshots/tests.js.md index 68324a356a..af83f51ebd 100644 --- a/packages/build/tests/telemetry/snapshots/tests.js.md +++ b/packages/build/tests/telemetry/snapshots/tests.js.md @@ -120,7 +120,7 @@ Generated by [AVA](https://avajs.dev). plugins: [], siteId: 'test', status: 'success', - steps: 1, + steps: 2, }, timestamp: 'number', userId: 'buildbot_user', @@ -156,7 +156,7 @@ Generated by [AVA](https://avajs.dev). ], siteId: 'test', status: 'success', - steps: 2, + steps: 3, }, timestamp: 'number', userId: 'buildbot_user', @@ -192,7 +192,7 @@ Generated by [AVA](https://avajs.dev). ], siteId: 'test', status: 'success', - steps: 2, + steps: 3, }, timestamp: 'number', userId: 'buildbot_user', @@ -228,7 +228,7 @@ Generated by [AVA](https://avajs.dev). ], siteId: 'test', status: 'success', - steps: 2, + steps: 3, }, timestamp: 'number', userId: 'buildbot_user', @@ -264,7 +264,7 @@ Generated by [AVA](https://avajs.dev). ], siteId: 'test', status: 'success', - steps: 2, + steps: 3, }, timestamp: 'number', userId: 'buildbot_user', diff --git a/packages/build/tests/telemetry/snapshots/tests.js.snap b/packages/build/tests/telemetry/snapshots/tests.js.snap index c336d43755..8391495719 100644 Binary files a/packages/build/tests/telemetry/snapshots/tests.js.snap and b/packages/build/tests/telemetry/snapshots/tests.js.snap differ diff --git a/packages/build/tests/time/snapshots/tests.js.md b/packages/build/tests/time/snapshots/tests.js.md index 0b77e7432a..72173d1b6e 100644 --- a/packages/build/tests/time/snapshots/tests.js.md +++ b/packages/build/tests/time/snapshots/tests.js.md @@ -12,6 +12,7 @@ Generated by [AVA](https://avajs.dev). buildbot.build.stage.duration:0|d|#stage:frameworks_api_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:get_plugins_options,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:others,parent:run_netlify_build␊ + buildbot.build.stage.duration:0|d|#stage:pre_cleanup,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:resolve_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:start_plugins,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:system,parent:run_netlify_build_per_type␊ @@ -32,6 +33,7 @@ Generated by [AVA](https://avajs.dev). buildbot.build.stage.duration:0|d|#stage:onPostBuild,parent:netlify_plugin_sitemap␊ buildbot.build.stage.duration:0|d|#stage:others,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:plugin,parent:run_netlify_build_per_type␊ + buildbot.build.stage.duration:0|d|#stage:pre_cleanup,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:resolve_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:run_plugins,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:start_plugins,parent:run_netlify_build␊ @@ -48,6 +50,7 @@ Generated by [AVA](https://avajs.dev). buildbot.build.stage.duration:0|d|#stage:load_plugins,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:others,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:plugin,parent:run_netlify_build_per_type␊ + buildbot.build.stage.duration:0|d|#stage:pre_cleanup,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:resolve_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:run_plugins,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:start_plugins,parent:run_netlify_build␊ @@ -64,6 +67,7 @@ Generated by [AVA](https://avajs.dev). buildbot.build.stage.duration:0|d|#stage:functions_bundling,parent:run_netlify_build,bundler:zisi␊ buildbot.build.stage.duration:0|d|#stage:get_plugins_options,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:others,parent:run_netlify_build␊ + buildbot.build.stage.duration:0|d|#stage:pre_cleanup,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:resolve_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:start_plugins,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:system,parent:run_netlify_build_per_type␊ @@ -79,6 +83,7 @@ Generated by [AVA](https://avajs.dev). buildbot.build.stage.duration:0|d|#stage:frameworks_api_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:get_plugins_options,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:others,parent:run_netlify_build␊ + buildbot.build.stage.duration:0|d|#stage:pre_cleanup,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:resolve_config,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:start_plugins,parent:run_netlify_build␊ buildbot.build.stage.duration:0|d|#stage:system,parent:run_netlify_build_per_type␊ diff --git a/packages/build/tests/time/snapshots/tests.js.snap b/packages/build/tests/time/snapshots/tests.js.snap index 02be8d6281..685cb28dac 100644 Binary files a/packages/build/tests/time/snapshots/tests.js.snap and b/packages/build/tests/time/snapshots/tests.js.snap differ