From e037fbf0b4ecddc6775c56eb6f58eb8570226827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Thu, 6 Jun 2024 16:18:41 +0100 Subject: [PATCH] feat: populate Blobs context in build plugins (#5571) * feat: populate Blobs context in build plugins * chore: fix test * chore: update test * chore: fix test * chore: fix formatting * chore: fix test * chore: update test * chore: update tests --- packages/build/src/core/build.ts | 11 +- packages/build/src/core/feature_flags.ts | 1 + packages/build/src/core/normalize_flags.ts | 3 +- .../src/plugins_core/blobs_upload/index.ts | 3 +- packages/build/src/utils/blobs.ts | 36 +++++ .../build/tests/install/snapshots/tests.js.md | 129 ------------------ .../tests/install/snapshots/tests.js.snap | Bin 2791 -> 2534 bytes packages/build/tests/install/tests.js | 23 +++- .../plugins/fixtures/blobs_read/manifest.yml | 2 + .../plugins/fixtures/blobs_read/netlify.toml | 2 + .../plugins/fixtures/blobs_read/plugin.js | 18 +++ packages/build/tests/plugins/tests.js | 38 +++++- packages/testing/src/server.ts | 4 +- 13 files changed, 130 insertions(+), 140 deletions(-) create mode 100644 packages/build/tests/plugins/fixtures/blobs_read/manifest.yml create mode 100644 packages/build/tests/plugins/fixtures/blobs_read/netlify.toml create mode 100644 packages/build/tests/plugins/fixtures/blobs_read/plugin.js diff --git a/packages/build/src/core/build.ts b/packages/build/src/core/build.ts index d699e8de31..891e3b2d4f 100644 --- a/packages/build/src/core/build.ts +++ b/packages/build/src/core/build.ts @@ -14,6 +14,7 @@ import { reportStatuses } from '../status/report.js' import { getDevSteps, getSteps } from '../steps/get.js' import { runSteps } from '../steps/run_steps.js' import { initTimers, measureDuration } from '../time/main.js' +import { getBlobsEnvironmentContext } from '../utils/blobs.js' import { getConfigOpts, loadConfig } from './config.js' import { getConstants } from './constants.js' @@ -197,6 +198,7 @@ const tExecBuild = async function ({ dry, mode, api, + token, errorMonitor, deployId, errorParams, @@ -258,6 +260,7 @@ export const runAndReportBuild = async function ({ dry, mode, api, + token, errorMonitor, deployId, errorParams, @@ -310,6 +313,7 @@ export const runAndReportBuild = async function ({ dry, mode, api, + token, errorMonitor, deployId, errorParams, @@ -414,6 +418,7 @@ const initAndRunBuild = async function ({ dry, mode, api, + token, errorMonitor, deployId, errorParams, @@ -459,6 +464,10 @@ const initAndRunBuild = async function ({ systemLog, }) + const pluginsEnv = featureFlags.build_inject_blobs_context + ? { ...childEnv, ...getBlobsEnvironmentContext({ api, deployId: deployId, siteId: siteInfo?.id, token }) } + : childEnv + if (pluginsOptionsA?.length) { const buildPlugins = {} for (const plugin of pluginsOptionsA) { @@ -475,7 +484,7 @@ const initAndRunBuild = async function ({ const { childProcesses, timers: timersB } = await startPlugins({ pluginsOptions: pluginsOptionsA, buildDir, - childEnv, + childEnv: pluginsEnv, logs, debug, timers: timersA, diff --git a/packages/build/src/core/feature_flags.ts b/packages/build/src/core/feature_flags.ts index a3e5c0ead0..253579d40d 100644 --- a/packages/build/src/core/feature_flags.ts +++ b/packages/build/src/core/feature_flags.ts @@ -15,6 +15,7 @@ const getFeatureFlag = function (name: string): FeatureFlags { // Default values for feature flags export const DEFAULT_FEATURE_FLAGS: FeatureFlags = { + build_inject_blobs_context: false, buildbot_zisi_trace_nft: false, buildbot_zisi_esbuild_parser: false, buildbot_zisi_system_log: false, diff --git a/packages/build/src/core/normalize_flags.ts b/packages/build/src/core/normalize_flags.ts index 3d83fb9c55..2eb19c900a 100644 --- a/packages/build/src/core/normalize_flags.ts +++ b/packages/build/src/core/normalize_flags.ts @@ -6,6 +6,7 @@ import { removeFalsy } from '../utils/remove_falsy.js' import { DEFAULT_FEATURE_FLAGS } from './feature_flags.js' import type { BuildFlags, Mode, TestOptions } from './types.js' +export const DEFAULT_API_HOST = 'api.netlify.com' const REQUIRE_MODE: Mode = 'require' const DEFAULT_EDGE_FUNCTIONS_DIST = '.netlify/edge-functions-dist/' const DEFAULT_FUNCTIONS_DIST = '.netlify/functions/' @@ -91,7 +92,7 @@ const getDefaultFlags = function ({ env: envOpt = {} }, combinedEnv) { bugsnagKey: combinedEnv.BUGSNAG_KEY, sendStatus: false, saveConfig: false, - apiHost: 'api.netlify.com', + apiHost: DEFAULT_API_HOST, testOpts: {}, featureFlags: DEFAULT_FEATURE_FLAGS, statsd: { port: DEFAULT_STATSD_PORT }, diff --git a/packages/build/src/plugins_core/blobs_upload/index.ts b/packages/build/src/plugins_core/blobs_upload/index.ts index f9fc5e9619..468d6ecd0a 100644 --- a/packages/build/src/plugins_core/blobs_upload/index.ts +++ b/packages/build/src/plugins_core/blobs_upload/index.ts @@ -4,6 +4,7 @@ import { getDeployStore } from '@netlify/blobs' import pMap from 'p-map' import semver from 'semver' +import { DEFAULT_API_HOST } from '../../core/normalize_flags.js' import { log, logError } from '../../log/logger.js' import { getFileWithMetadata, getKeysToUpload, scanForBlobs } from '../../utils/blobs.js' import { type CoreStep, type CoreStepCondition, type CoreStepFunction } from '../types.js' @@ -22,7 +23,7 @@ const coreStep: CoreStepFunction = async function ({ return {} } // for cli deploys with `netlify deploy --build` the `NETLIFY_API_HOST` is undefined - const apiHost = NETLIFY_API_HOST || 'api.netlify.com' + const apiHost = NETLIFY_API_HOST || DEFAULT_API_HOST const storeOpts: Parameters[0] = { siteID: SITE_ID, diff --git a/packages/build/src/utils/blobs.ts b/packages/build/src/utils/blobs.ts index 15bfb6958b..7254762870 100644 --- a/packages/build/src/utils/blobs.ts +++ b/packages/build/src/utils/blobs.ts @@ -3,6 +3,8 @@ import path from 'node:path' import { fdir } from 'fdir' +import { DEFAULT_API_HOST } from '../core/normalize_flags.js' + const LEGACY_BLOBS_PATH = '.netlify/blobs/deploy' const DEPLOY_CONFIG_BLOBS_PATH = '.netlify/deploy/v1/blobs/deploy' @@ -12,6 +14,40 @@ export const getBlobsDirs = (buildDir: string, packagePath?: string) => [ path.resolve(buildDir, packagePath || '', LEGACY_BLOBS_PATH), ] +interface EnvironmentContext { + api?: { + host: string + scheme: string + } + deployId?: string + siteId?: string + token?: string +} + +// TODO: Move this work to a method exported by `@netlify/blobs`. +export const getBlobsEnvironmentContext = ({ + api = { host: DEFAULT_API_HOST, scheme: 'https' }, + deployId, + siteId, + token, +}: EnvironmentContext) => { + if (!deployId || !siteId || !token) { + return {} + } + + const payload = { + apiURL: `${api.scheme}://${api.host}`, + deployID: deployId, + siteID: siteId, + token, + } + const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64') + + return { + NETLIFY_BLOBS_CONTEXT: encodedPayload, + } +} + /** * Detect if there are any blobs to upload, and if so, what directory they're * in and whether that directory is the legacy `.netlify/blobs` path or the diff --git a/packages/build/tests/install/snapshots/tests.js.md b/packages/build/tests/install/snapshots/tests.js.md index ff4bfb1ff3..9b23f807b5 100644 --- a/packages/build/tests/install/snapshots/tests.js.md +++ b/packages/build/tests/install/snapshots/tests.js.md @@ -598,73 +598,6 @@ Generated by [AVA](https://avajs.dev). (Netlify Build completed in 1ms)␊ Build step duration: Netlify Build completed in 1ms` -## Functions: install dependencies handles errors - -> Snapshot 1 - - `␊ - Netlify Build ␊ - ────────────────────────────────────────────────────────────────␊ - ␊ - > Version␊ - @netlify/build 1.0.0␊ - ␊ - > Flags␊ - debug: true␊ - repositoryRoot: packages/build/tests/install/fixtures/functions_error␊ - testOpts:␊ - pluginsListUrl: test␊ - silentLingeringProcesses: true␊ - ␊ - > Current directory␊ - packages/build/tests/install/fixtures/functions_error␊ - ␊ - > Config file␊ - packages/build/tests/install/fixtures/functions_error/netlify.toml␊ - ␊ - > Resolved config␊ - build:␊ - publish: packages/build/tests/install/fixtures/functions_error␊ - publishOrigin: default␊ - functionsDirectory: packages/build/tests/install/fixtures/functions_error/functions␊ - plugins:␊ - - inputs: {}␊ - origin: config␊ - package: '@netlify/plugin-functions-install-core'␊ - ␊ - > Context␊ - production␊ - ␊ - @netlify/plugin-functions-install-core (onPreBuild event) ␊ - ────────────────────────────────────────────────────────────────␊ - ␊ - Installing functions dependencies␊ - ␊ - Dependencies installation error ␊ - ────────────────────────────────────────────────────────────────␊ - ␊ - Error message␊ - Error while installing dependencies in packages/build/tests/install/fixtures/functions_error/functions␊ - npm ERR! code ENOVERSIONS␊ - npm ERR! No versions available for math-avg-does-not-exist␊ - ␊ - Plugin details␊ - Package: @netlify/plugin-functions-install-core␊ - Version: 1.0.0␊ - Repository: git+https://github.com/netlify/build.git␊ - npm link: https://www.npmjs.com/package/@netlify/build␊ - Report issues: https://github.com/netlify/build/issues␊ - ␊ - Resolved config␊ - build:␊ - publish: packages/build/tests/install/fixtures/functions_error␊ - publishOrigin: default␊ - functionsDirectory: packages/build/tests/install/fixtures/functions_error/functions␊ - plugins:␊ - - inputs: {}␊ - origin: config␊ - package: '@netlify/plugin-functions-install-core'` - ## Install local plugin dependencies: with npm > Snapshot 1 @@ -846,68 +779,6 @@ Generated by [AVA](https://avajs.dev). (Netlify Build completed in 1ms)␊ Build step duration: Netlify Build completed in 1ms` -## Install local plugin dependencies: propagate errors - -> Snapshot 1 - - `␊ - Netlify Build ␊ - ────────────────────────────────────────────────────────────────␊ - ␊ - > Version␊ - @netlify/build 1.0.0␊ - ␊ - > Flags␊ - debug: true␊ - repositoryRoot: packages/build/tests/install/fixtures/error␊ - testOpts:␊ - pluginsListUrl: test␊ - silentLingeringProcesses: true␊ - ␊ - > Current directory␊ - packages/build/tests/install/fixtures/error␊ - ␊ - > Config file␊ - packages/build/tests/install/fixtures/error/netlify.toml␊ - ␊ - > Resolved config␊ - build:␊ - publish: packages/build/tests/install/fixtures/error␊ - publishOrigin: default␊ - plugins:␊ - - inputs: {}␊ - origin: config␊ - package: '@netlify/plugin-local-install-core'␊ - - inputs: {}␊ - origin: config␊ - package: ./plugin/main.js␊ - ␊ - > Context␊ - production␊ - ␊ - > Installing local plugins dependencies␊ - - ./plugin/main.js␊ - ␊ - Dependencies installation error ␊ - ────────────────────────────────────────────────────────────────␊ - ␊ - Error message␊ - Error while installing dependencies in packages/build/tests/install/fixtures/error/plugin␊ - npm ERR! code ENOVERSIONS␊ - npm ERR! No versions available for this-dependency-does-not-exist␊ - ␊ - Resolved config␊ - build:␊ - publish: packages/build/tests/install/fixtures/error␊ - publishOrigin: default␊ - plugins:␊ - - inputs: {}␊ - origin: config␊ - package: '@netlify/plugin-local-install-core'␊ - - inputs: {}␊ - origin: config␊ - package: ./plugin/main.js` - ## Install local plugin dependencies: already installed > Snapshot 1 diff --git a/packages/build/tests/install/snapshots/tests.js.snap b/packages/build/tests/install/snapshots/tests.js.snap index 7db5dbd941cfa39f5ca5c86fd4a03f53c02eaf69..8828ee6096bd6dfb00e898a6dedc1ef40ea1da35 100644 GIT binary patch literal 2534 zcmVzpvg_I3iPUP(5s#q{*I(w{ZOPBc?4py zOLESfIe*_bq-OSqVc(^L*X&P!!QA04zI^|2NCw=Ygqg@8j9adYZ0uuVV={0sLj*I9 zZHE!dXJg9Q_dnRS#jUU3{py!DZru={U);R$-aGf-HJ)MaI>RY?7&@+v*8Ld&{_}S~ z>%%baqu=9zfh`S$9+1cyoxZfjQTwCzN8*mht~FwC-NyZJWFj7f82$>dPnpAMFzr&x zP2^jH*VYKLsC9>f4_GI5PiN>{@-Tplwi7^Gaq-OO%rt}fWT;flnk8_8bVL&H0{KuYIEwj zLQWSm>Q1nY22vo%k|N>(hJDvznrXyDa$2eAR@`%IKm**24bAbT(B2QI9m?Ab zV>JQjkdpHNM@fn&;P5;9l7CO4VM26gUR8>jVH~b#q@0Zg)bm{oH4r?Cjy!h9h|WV< z^pPC~mS}FG;(`q$t;G=V#FhhjyDI3p%my*;%oM|bdU=1QX=*@{CFdbKZG74O28?JN zE->SYPF$g-F@tj_@%6XJONXijRp5?`v*SIX8)YQxATUD6=6)iJO2l%2bvum{&>F8c9Fb=8eK(h~_XmQ|Qy&7LAcw73MKQN<~B_He<<5Mh-|*nc5th%Iw?)g*~XLOl^;HsZ3{eDgzBq zo-80Te^ZFeUp0{_KxDx5E}cHHO{C&oZ{WaHkJ{uVogZdDdug_)5B?!R(DlA zikA#nb3Hd1YUCFeG>{cw*@YECWdKjfH{@AgZRqCt7{g8CMusOiuv~OuO&Q`8O423h z45NYk>AToV9(Q%IM<-%@QyK=>bxv$#*|xZokFh!i5HHSw?S>W;H9>a4tfBZ73SKDmXeU~Rgh(e4-%Cc^K;XNEc%s)xtSHAY??Mt? z=qD7ygPsz}$Jv;M)OG2F_$$H_F)rD#k*~-NQ~2}c%NTQBy~+wb`W!V@d!E#gF(LIC zT8;=5$wH2z)H7p%TdPW@i;U1|w|mw#p=5?2UIa`K0Z1-{MfYzztR&p=<(9bPT?BD8 zRaz{dlg4X>PX2LrVzBOK59;vF=%nyhO*y5aT2W$|7gi0soUv@(YJp-9%`=y$sOFgk zjJF=oRGF1vnPY2$ui%zu4%6?V1{+&}-_U$h^Uc-x=DjEd*(!u{am`$hb(Yyn7W*2} zW-0E2MHJTu_QD}w0}<&AU5uf)4Dqo z!CzICHeJ!47gFxJ_8AM7v$|awj%J(76G^|utL;(lYrM}k#3{L2XaPojqF~ga#;D3M zN_wU~_>`%$AvUD~O2wtT)k?vnY#17kmM4wIquL(j;?alkSCb=vNv7%fXA$N#+ie{D zQ-PnqYxt=germJHMuDw0%HB|8={6c$ULYZJX=ZW6Mv~jH#Exe9P^st4u>Nw5bwp@zEEODo zyDB(Nuien$;J*q={!61|0hgmPbo z<_)*!_*oDD&!ghdm~A0eM{pbvs2|rX@Y#c;o?q9KElY4bp9VZOt(o5X^0eFSeRcNe z#naQ?v$N;D$7e5|J$hxL6N`veLxz>aMMw$UK=jNO~FbIW1*-s zXj!vPbZ2IIkvBXltA7|nIe`;VOfQJa`4Ily^W&2*(ev){$!R7Ma>U00kEr9fkY?gx zU~`e*n&{28mz(Tc`AK-iC#&&_fQs+?UP~?x-c!iMJ9T*W(pH#sdbCTX73V zJ~tM;W1X4HYPi|a5|Y?)^_b48DivBv5(}wdIZ0;0(x6e#KC4T^de1)9;I4K88o~R% zP7!yO%n8iCdO~E5jUsf0{wDG(Gk4QXv(&dSVw;WRirDrd-&QW>9MWJQ93qE355YG- zS0K23Q$z4N5Il(LuZW9D8Hn7=`Ew4P2N$*oq;=(VY69)b*tP-l${;I){23QrSuqr} w7U2RXWR6AK-K8>Ou(tYxRz8_!^=x-$Y?k2s()N0GRLbn=|4wp86IG1>0JOp1zyJUM literal 2791 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 diff --git a/packages/build/tests/install/tests.js b/packages/build/tests/install/tests.js index 62805c546a..343da99ad0 100644 --- a/packages/build/tests/install/tests.js +++ b/packages/build/tests/install/tests.js @@ -1,3 +1,4 @@ +import { join } from 'path' import { fileURLToPath } from 'url' import { Fixture, normalizeOutput, removeDir } from '@netlify/testing' @@ -11,18 +12,23 @@ const FIXTURES_DIR = fileURLToPath(new URL('fixtures', import.meta.url)) // - specific directories are removed before/after test // TODO: once we have a test runner that supports before and after this would be way nicer to read to remove dirs there -const runInstallFixture = async (t, fixtureName, dirs = [], flags = {}, binary = false) => { +const runInstallFixture = async (t, fixtureName, dirs = [], flags = {}, binary = false, useSnapshot = true) => { await removeDir(dirs) try { const fixture = new Fixture(`./fixtures/${fixtureName}`).withFlags(flags) const result = binary ? await fixture.runBuildBinary().then(({ output }) => output) : await fixture.runWithBuild() - t.snapshot(normalizeOutput(result)) + if (useSnapshot) { + t.snapshot(normalizeOutput(result)) + } + await Promise.all( dirs.map(async (dir) => { t.true(await pathExists(dir)) }), ) + + return { fixture, result } } finally { await removeDir(dirs) } @@ -95,7 +101,10 @@ test('Functions: does not print warnings when dependency was local', async (t) = }) test('Functions: install dependencies handles errors', async (t) => { - await runInstallFixture(t, 'functions_error') + const { fixture, result } = await runInstallFixture(t, 'functions_error', [], {}, false, false) + const functionsPath = join(fixture.repositoryRoot, 'functions') + + t.true(result.includes(`Error while installing dependencies in ${functionsPath}`)) }) test('Install local plugin dependencies: with npm', async (t) => { @@ -114,8 +123,12 @@ test('Install local plugin dependencies: with yarn in CI', async (t) => { }) test('Install local plugin dependencies: propagate errors', async (t) => { - const output = await new Fixture('./fixtures/error').runWithBuild() - t.snapshot(normalizeOutput(output)) + const fixture = new Fixture('./fixtures/error') + const { success, output } = await fixture.runWithBuildAndIntrospect() + const pluginPath = join(fixture.repositoryRoot, 'plugin') + + t.false(success) + t.true(output.includes(`Error while installing dependencies in ${pluginPath}`)) }) test('Install local plugin dependencies: already installed', async (t) => { diff --git a/packages/build/tests/plugins/fixtures/blobs_read/manifest.yml b/packages/build/tests/plugins/fixtures/blobs_read/manifest.yml new file mode 100644 index 0000000000..a3512f0259 --- /dev/null +++ b/packages/build/tests/plugins/fixtures/blobs_read/manifest.yml @@ -0,0 +1,2 @@ +name: test +inputs: [] diff --git a/packages/build/tests/plugins/fixtures/blobs_read/netlify.toml b/packages/build/tests/plugins/fixtures/blobs_read/netlify.toml new file mode 100644 index 0000000000..81b0ce8bb1 --- /dev/null +++ b/packages/build/tests/plugins/fixtures/blobs_read/netlify.toml @@ -0,0 +1,2 @@ +[[plugins]] +package = "./plugin" diff --git a/packages/build/tests/plugins/fixtures/blobs_read/plugin.js b/packages/build/tests/plugins/fixtures/blobs_read/plugin.js new file mode 100644 index 0000000000..9027adb9c0 --- /dev/null +++ b/packages/build/tests/plugins/fixtures/blobs_read/plugin.js @@ -0,0 +1,18 @@ +import { version as nodeVersion } from "process" + +import { getDeployStore } from '@netlify/blobs' +import semver from 'semver' + +export const onPreBuild = async function ({netlifyConfig}) { + const storeOptions = {} + + if (semver.lt(nodeVersion, '18.0.0')) { + const nodeFetch = await import('node-fetch') + storeOptions.fetch = nodeFetch.default + } + + const store = getDeployStore(storeOptions) + const value = await store.get("my-key") + + netlifyConfig.build.command = `echo "${value}"` +} diff --git a/packages/build/tests/plugins/tests.js b/packages/build/tests/plugins/tests.js index 9bea23fe4c..063224e896 100644 --- a/packages/build/tests/plugins/tests.js +++ b/packages/build/tests/plugins/tests.js @@ -2,8 +2,9 @@ import * as fs from 'fs/promises' import { platform } from 'process' import { fileURLToPath } from 'url' -import { Fixture, normalizeOutput, removeDir } from '@netlify/testing' +import { Fixture, normalizeOutput, removeDir, startServer } from '@netlify/testing' import test from 'ava' +import getPort from 'get-port' import tmp, { tmpName } from 'tmp-promise' import { DEFAULT_FEATURE_FLAGS } from '../../lib/core/feature_flags.js' @@ -366,3 +367,38 @@ test('Plugin errors that occur during the loading phase are piped to system logs t.snapshot(normalizeOutput(output)) }) + +test('Plugins have a pre-populated Blobs context', async (t) => { + const serverPort = await getPort() + const deployId = 'deploy123' + const siteId = 'site321' + const token = 'some-token' + const { scheme, host, stopServer } = await startServer( + [ + { + response: { url: `http://localhost:${serverPort}/some-signed-url` }, + path: `/api/v1/blobs/${siteId}/deploy:${deployId}/my-key`, + }, + { + response: 'Hello there', + path: `/some-signed-url`, + }, + ], + serverPort, + ) + + const { netlifyConfig } = await new Fixture('./fixtures/blobs_read') + .withFlags({ + apiHost: host, + deployId, + featureFlags: { build_inject_blobs_context: true }, + testOpts: { scheme }, + siteId, + token, + }) + .runWithBuildAndIntrospect() + + await stopServer() + + t.is(netlifyConfig.build.command, `echo ""Hello there""`) +}) diff --git a/packages/testing/src/server.ts b/packages/testing/src/server.ts index 70a7ee0efc..7b35505b0e 100644 --- a/packages/testing/src/server.ts +++ b/packages/testing/src/server.ts @@ -26,12 +26,12 @@ const setTimeoutPromise = promisify(setTimeout) // response: json payload response (defaults to {}) // status: http status code (defaults to 200) // wait: number used to induce a certain time delay in milliseconds in the response (defaults to undefined) -export const startServer = async (handler: ServerHandler) => { +export const startServer = async (handler: ServerHandler, port = 0) => { const handlers = Array.isArray(handler) ? handler : [handler] const requests: Request[] = [] const server = createServer((req, res) => requestHandler(req, res, requests, handlers)) - await promisify(server.listen.bind(server))(0) + await promisify(server.listen.bind(server))(port) const host = getHost(server)