From 6086dd0ea1fc8e9f31811a90ef30432f29b93a8d Mon Sep 17 00:00:00 2001 From: Lukas Holzer Date: Mon, 18 Dec 2023 10:51:40 +0100 Subject: [PATCH 1/4] feat(build-info): pass feature flags as json and change plugins to an object BREAKING CHANGE: Plugin build settings now use an object array, not string lists, allowing extra details like install source and if always needed at runtime. --- .../build-info/src/build-systems/nx.test.ts | 8 +-- .../build-info/src/frameworks/angular.test.ts | 2 +- packages/build-info/src/frameworks/angular.ts | 2 +- .../build-info/src/frameworks/framework.ts | 13 +++-- .../build-info/src/frameworks/gatsby.test.ts | 7 ++- packages/build-info/src/frameworks/gatsby.ts | 2 +- .../build-info/src/frameworks/next.test.ts | 54 +++++++++++++++++-- packages/build-info/src/frameworks/next.ts | 13 ++++- .../__snapshots__/get-build-info.test.ts.snap | 25 ++++----- packages/build-info/src/node/bin.ts | 23 ++++---- .../build-info/src/node/get-build-info.ts | 3 +- packages/build-info/src/project.ts | 7 +++ .../src/settings/get-build-settings.test.ts | 10 ++-- .../src/settings/get-build-settings.ts | 9 ++-- .../src/settings/get-toml-settings.test.ts | 2 +- .../src/settings/get-toml-settings.ts | 9 +++- .../tests/__snapshots__/bin.test.ts.snap | 11 ++-- 17 files changed, 138 insertions(+), 62 deletions(-) diff --git a/packages/build-info/src/build-systems/nx.test.ts b/packages/build-info/src/build-systems/nx.test.ts index fee6d54999..6f2b6f284b 100644 --- a/packages/build-info/src/build-systems/nx.test.ts +++ b/packages/build-info/src/build-systems/nx.test.ts @@ -197,7 +197,7 @@ describe('nx-integrated project.json based', () => { frameworkPort: 4200, name: `Nx + Next.js ${join('packages/website')}`, packagePath: join('packages/website'), - plugins_recommended: ['@netlify/plugin-nextjs'], + plugins: [{ name: '@netlify/plugin-nextjs', alwaysInstall: true }], }), ]), ) @@ -212,7 +212,7 @@ describe('nx-integrated project.json based', () => { frameworkPort: 3000, name: `Nx + Astro ${join('packages/astro')}`, packagePath: join('packages/astro'), - plugins_recommended: [], + plugins: [], }), ]), ) @@ -250,7 +250,7 @@ describe('nx-integrated workspace.json based', () => { frameworkPort: 4200, name: `Nx + React Static ${join('apps/website')}`, packagePath: join('apps/website'), - plugins_recommended: [], + plugins: [], }), ]), ) @@ -264,7 +264,7 @@ describe('nx-integrated workspace.json based', () => { framework: { id: 'astro', name: 'Astro' }, name: `Nx + Astro ${join('apps/astro')}`, packagePath: join('apps/astro'), - plugins_recommended: [], + plugins: [], }), ]), ) diff --git a/packages/build-info/src/frameworks/angular.test.ts b/packages/build-info/src/frameworks/angular.test.ts index 966ae11641..83ab49668f 100644 --- a/packages/build-info/src/frameworks/angular.test.ts +++ b/packages/build-info/src/frameworks/angular.test.ts @@ -31,7 +31,7 @@ test('should detect Angular', async ({ fs }) => { expect(detected?.[0].build.command).toBe('ng build --prod') expect(detected?.[0].build.directory).toBe(fs.join('dist', 'demo', 'browser')) expect(detected?.[0].dev?.command).toBe('ng serve') - expect(detected?.[0].plugins).toEqual(['@netlify/angular-runtime']) + expect(detected?.[0].plugins).toEqual([{ name: '@netlify/angular-runtime' }]) }) test('should only install plugin on v17+', async ({ fs }) => { diff --git a/packages/build-info/src/frameworks/angular.ts b/packages/build-info/src/frameworks/angular.ts index cd50c4bd6b..2bbfe1317a 100644 --- a/packages/build-info/src/frameworks/angular.ts +++ b/packages/build-info/src/frameworks/angular.ts @@ -31,7 +31,7 @@ export class Angular extends BaseFramework implements Framework { if (this.detected) { if (this.version && gte(this.version, '17.0.0-rc')) { - this.plugins.push('@netlify/angular-runtime') + this.plugins.push({ name: '@netlify/angular-runtime' }) const angularJson = await this.project.fs.gracefullyReadFile('angular.json') if (angularJson) { const { projects, defaultProject } = JSON.parse(angularJson) diff --git a/packages/build-info/src/frameworks/framework.ts b/packages/build-info/src/frameworks/framework.ts index c31311b900..396ab888ae 100644 --- a/packages/build-info/src/frameworks/framework.ts +++ b/packages/build-info/src/frameworks/framework.ts @@ -39,6 +39,13 @@ export type Detection = { export type FrameworkInfo = ReturnType +export type BuildPlugin = { + name: string + /** Plugins that should be always installed */ + alwaysInstall?: boolean + source?: 'toml' +} + export interface Framework { project: Project @@ -67,7 +74,7 @@ export interface Framework { light?: string dark?: string } - plugins: string[] + plugins: BuildPlugin[] env: Record detect(): Promise @@ -147,7 +154,7 @@ export abstract class BaseFramework implements Framework { configFiles: string[] = [] npmDependencies: string[] = [] excludedNpmDependencies: string[] = [] - plugins: string[] = [] + plugins: BuildPlugin[] = [] staticAssetsDirectory?: string env = {} dev?: { @@ -355,7 +362,7 @@ export abstract class BaseFramework implements Framework { {}, ) : undefined, - plugins: this.plugins, + plugins: this.plugins.map(({ name }) => name), } } } diff --git a/packages/build-info/src/frameworks/gatsby.test.ts b/packages/build-info/src/frameworks/gatsby.test.ts index 1dc6f92cb3..38b0f35df5 100644 --- a/packages/build-info/src/frameworks/gatsby.test.ts +++ b/packages/build-info/src/frameworks/gatsby.test.ts @@ -16,7 +16,7 @@ test('should not add the plugin if the node version is below 12.13.0', async ({ fs.cwd = cwd const detected = await new Project(fs, cwd).setNodeVersion('12.12.9').detectFrameworks() expect(detected?.[0].id).toBe('gatsby') - expect(detected?.[0].plugins).toMatchObject([]) + expect(detected?.[0].plugins).toHaveLength(0) }) test('should detect a simple Gatsby project and add the plugin if the node version is large enough', async ({ fs }) => { @@ -27,7 +27,7 @@ test('should detect a simple Gatsby project and add the plugin if the node versi fs.cwd = cwd const detected = await new Project(fs, cwd).setNodeVersion('12.13.0').detectFrameworks() expect(detected?.[0].id).toBe('gatsby') - expect(detected?.[0].plugins).toMatchObject(['@netlify/plugin-gatsby']) + expect(detected?.[0].plugins).toMatchObject([{ name: '@netlify/plugin-gatsby' }]) }) test('should detect a simple Gatsby 4 project', async ({ fs }) => { @@ -67,8 +67,7 @@ test('should detect a simple Gatsby 4 project', async ({ fs }) => { frameworkPort: 8000, name: 'Gatsby', packagePath: '', - plugins_from_config_file: [], - plugins_recommended: [], + plugins: [], pollingStrategies: ['TCP', 'HTTP'], }, ]) diff --git a/packages/build-info/src/frameworks/gatsby.ts b/packages/build-info/src/frameworks/gatsby.ts index a5eed74466..745563ace9 100644 --- a/packages/build-info/src/frameworks/gatsby.ts +++ b/packages/build-info/src/frameworks/gatsby.ts @@ -45,7 +45,7 @@ export class Gatsby extends BaseFramework implements Framework { const nodeVersion = await this.project.getCurrentNodeVersion() if (nodeVersion && gte(nodeVersion, '12.13.0')) { - this.plugins.push('@netlify/plugin-gatsby') + this.plugins.push({ name: '@netlify/plugin-gatsby' }) } return this as DetectedFramework } diff --git a/packages/build-info/src/frameworks/next.test.ts b/packages/build-info/src/frameworks/next.test.ts index 5a4dc4c8f6..e4dafe3eca 100644 --- a/packages/build-info/src/frameworks/next.test.ts +++ b/packages/build-info/src/frameworks/next.test.ts @@ -38,7 +38,15 @@ describe('Next.js Plugin', () => { const project = new Project(fs, cwd).setNodeVersion('v10.13.0') const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual(['@netlify/plugin-nextjs']) + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) + }) + + test('Should use the old runtime if the next.js version is not >= 13.5.0', async ({ fs, cwd }) => { + const project = new Project(fs, cwd).setNodeVersion('v18.0.0') + project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime' } + const frameworks = await project.detectFrameworks() + expect(frameworks?.[0].id).toBe('next') + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) }) test('Should not detect Next.js plugin for Next.js if when Node version < 10.13.0', async ({ fs, cwd }) => { @@ -49,6 +57,44 @@ describe('Next.js Plugin', () => { }) }) +describe('New Next.js Runtime', () => { + beforeEach((ctx) => { + ctx.cwd = mockFileSystem({ + 'package.json': JSON.stringify({ + name: 'my-next-app', + version: '0.1.0', + private: true, + scripts: { + dev: 'next dev', + build: 'next build', + start: 'next start', + }, + dependencies: { + next: '13.5.0', + react: '17.0.1', + 'react-dom': '17.0.1', + }, + }), + }) + }) + + test('Should not use the new runtime if the node version is below 18', async ({ fs, cwd }) => { + const project = new Project(fs, cwd).setNodeVersion('v16.0.0') + project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime@latest' } + const frameworks = await project.detectFrameworks() + expect(frameworks?.[0].id).toBe('next') + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) + }) + + test('Should use the old runtime if the next.js version is not >= 13.5.0', async ({ fs, cwd }) => { + const project = new Project(fs, cwd).setNodeVersion('v18.0.0') + project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime@latest' } + const frameworks = await project.detectFrameworks() + expect(frameworks?.[0].id).toBe('next') + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/next-runtime@latest', alwaysInstall: true }]) + }) +}) + describe('simple Next.js project', async () => { beforeEach((ctx) => { ctx.cwd = mockFileSystem({ @@ -90,7 +136,7 @@ describe('simple Next.js project', async () => { test('Should detect Next.js plugin for Next.js if when Node version >= 10.13.0', async ({ fs, cwd }) => { const detected = await new Project(fs, cwd).setEnvironment({ NODE_VERSION: '18.x' }).detectFrameworks() expect(detected?.[0].id).toBe('next') - expect(detected?.[0].plugins).toMatchObject(['@netlify/plugin-nextjs']) + expect(detected?.[0].plugins).toMatchObject([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) }) }) @@ -134,7 +180,7 @@ describe('Nx monorepo', () => { devCommand: 'nx run website:serve', dist: join('dist/packages/website'), frameworkPort: 4200, - plugins_recommended: ['@netlify/plugin-nextjs'], + plugins: [{ name: '@netlify/plugin-nextjs', alwaysInstall: true }], }) }) }) @@ -152,7 +198,7 @@ describe('Nx turborepo', () => { devCommand: 'turbo run dev --filter web', dist: join('apps/web/.next'), frameworkPort: 3000, - plugins_recommended: ['@netlify/plugin-nextjs'], + plugins: [{ name: '@netlify/plugin-nextjs', alwaysInstall: true }], }) }) }) diff --git a/packages/build-info/src/frameworks/next.ts b/packages/build-info/src/frameworks/next.ts index be9c0bc2fc..bbac82e1e2 100644 --- a/packages/build-info/src/frameworks/next.ts +++ b/packages/build-info/src/frameworks/next.ts @@ -32,8 +32,17 @@ export class Next extends BaseFramework implements Framework { if (this.detected) { const nodeVersion = await this.project.getCurrentNodeVersion() - if (nodeVersion && gte(nodeVersion, '10.13.0')) { - this.plugins.push('@netlify/plugin-nextjs') + const runtimeFromRollout = this.project.featureFlags['project_ceruledge_ui'] + if ( + nodeVersion && + gte(nodeVersion, '18.0.0') && + this.detected.package?.version && + gte(this.detected.package.version, '13.5.0') && + typeof runtimeFromRollout === 'string' + ) { + this.plugins.push({ name: runtimeFromRollout ?? '@netlify/plugin-nextjs', alwaysInstall: true }) + } else if (nodeVersion && gte(nodeVersion, '10.13.0')) { + this.plugins.push({ name: '@netlify/plugin-nextjs', alwaysInstall: true }) } return this as DetectedFramework } diff --git a/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap b/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap index 46739ecb9a..867e432206 100644 --- a/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap +++ b/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap @@ -64,8 +64,7 @@ exports[`should retrieve the build info for providing a rootDir 1`] = ` "frameworkPort": 3000, "name": "PNPM + Astro packages/blog", "packagePath": "packages/blog", - "plugins_from_config_file": [], - "plugins_recommended": [], + "plugins": [], "pollingStrategies": [ "TCP", "HTTP", @@ -84,9 +83,11 @@ exports[`should retrieve the build info for providing a rootDir 1`] = ` "frameworkPort": 3000, "name": "PNPM + Next.js packages/website", "packagePath": "packages/website", - "plugins_from_config_file": [], - "plugins_recommended": [ - "@netlify/plugin-nextjs", + "plugins": [ + { + "alwaysInstall": true, + "name": "@netlify/plugin-nextjs", + }, ], "pollingStrategies": [ "TCP", @@ -199,8 +200,7 @@ exports[`should retrieve the build info for providing a rootDir and a nested pro "frameworkPort": 3000, "name": "PNPM + Astro packages/blog", "packagePath": "packages/blog", - "plugins_from_config_file": [], - "plugins_recommended": [], + "plugins": [], "pollingStrategies": [ "TCP", "HTTP", @@ -274,8 +274,7 @@ exports[`should retrieve the build info for providing a rootDir and the same pro "frameworkPort": 3000, "name": "PNPM + Astro packages/blog", "packagePath": "packages/blog", - "plugins_from_config_file": [], - "plugins_recommended": [], + "plugins": [], "pollingStrategies": [ "TCP", "HTTP", @@ -294,9 +293,11 @@ exports[`should retrieve the build info for providing a rootDir and the same pro "frameworkPort": 3000, "name": "PNPM + Next.js packages/website", "packagePath": "packages/website", - "plugins_from_config_file": [], - "plugins_recommended": [ - "@netlify/plugin-nextjs", + "plugins": [ + { + "alwaysInstall": true, + "name": "@netlify/plugin-nextjs", + }, ], "pollingStrategies": [ "TCP", diff --git a/packages/build-info/src/node/bin.ts b/packages/build-info/src/node/bin.ts index 320a1650ba..d7927333fa 100644 --- a/packages/build-info/src/node/bin.ts +++ b/packages/build-info/src/node/bin.ts @@ -8,7 +8,11 @@ import { report } from '../metrics.js' import { getBuildInfo } from './get-build-info.js' import { initializeMetrics } from './metrics.js' -type Args = Arguments<{ projectDir?: string; rootDir?: string; featureFlags: Record }> +type Args = Arguments<{ + projectDir?: string + rootDir?: string + featureFlags: Record +}> yargs(hideBin(argv)) .command( @@ -22,13 +26,9 @@ yargs(hideBin(argv)) }, featureFlags: { string: true, - describe: 'comma separated list of feature flags', - coerce: (value = '') => - value - .split(',') - .map((flag) => flag.trim()) - .filter((flag) => flag.length) - .reduce((prev, cur) => ({ ...prev, [cur]: true }), {}), + describe: 'JSON stringified list of feature flags with values', + alias: 'ff', + coerce: (value: '{}') => JSON.parse(value), }, }), async ({ projectDir, rootDir, featureFlags }: Args) => { @@ -37,7 +37,12 @@ yargs(hideBin(argv)) try { console.log( JSON.stringify( - await getBuildInfo({ projectDir, rootDir, featureFlags, bugsnagClient }), + await getBuildInfo({ + projectDir, + rootDir, + featureFlags, + bugsnagClient, + }), // hide null values from the string output as we use null to identify it has already run but did not detect anything // undefined marks that it was never run (_, value) => (value !== null ? value : undefined), diff --git a/packages/build-info/src/node/get-build-info.ts b/packages/build-info/src/node/get-build-info.ts index 85b3360c6c..79a2b7b9c2 100644 --- a/packages/build-info/src/node/get-build-info.ts +++ b/packages/build-info/src/node/get-build-info.ts @@ -45,7 +45,7 @@ export async function getBuildInfo( config: { projectDir?: string rootDir?: string - featureFlags?: Record + featureFlags?: Record bugsnagClient?: Client } = { featureFlags: {} }, ): Promise { @@ -54,6 +54,7 @@ export async function getBuildInfo( fs.logger = new NoopLogger() const project = new Project(fs, config.projectDir, config.rootDir) .setBugsnag(config.bugsnagClient) + .setFeatureFlags(config.featureFlags) .setEnvironment(process.env) .setNodeVersion(process.version) diff --git a/packages/build-info/src/project.ts b/packages/build-info/src/project.ts index a528c047b4..56080b1e77 100644 --- a/packages/build-info/src/project.ts +++ b/packages/build-info/src/project.ts @@ -62,6 +62,8 @@ export class Project { bugsnag: Client /** A logging instance */ logger: Logger + /** A list of enabled feature flags */ + featureFlags: Record = {} /** A function that is used to report errors */ reportFn: typeof report = report @@ -76,6 +78,11 @@ export class Project { return this } + setFeatureFlags(flags: Record = {}): this { + this.featureFlags = { ...this.featureFlags, ...flags } + return this + } + async getCurrentNodeVersion(): Promise { if (this._nodeVersion) { return this._nodeVersion diff --git a/packages/build-info/src/settings/get-build-settings.test.ts b/packages/build-info/src/settings/get-build-settings.test.ts index 14b223727f..d99d5c7cea 100644 --- a/packages/build-info/src/settings/get-build-settings.test.ts +++ b/packages/build-info/src/settings/get-build-settings.test.ts @@ -17,7 +17,7 @@ beforeEach((ctx) => { test('get the settings for a next project', async (ctx) => { const fixture = await createFixture('next-project', ctx) - const project = new Project(ctx.fs, fixture.cwd) + const project = new Project(ctx.fs, fixture.cwd).setNodeVersion('18.0.0') const settings = await project.getBuildSettings() expect(settings).toEqual([ @@ -27,8 +27,7 @@ test('get the settings for a next project', async (ctx) => { dist: '.next', env: {}, frameworkPort: 3000, - plugins_recommended: [], - plugins_from_config_file: [], + plugins: [{ alwaysInstall: true, name: '@netlify/plugin-nextjs' }], pollingStrategies: ['TCP'], }), ]) @@ -36,7 +35,7 @@ test('get the settings for a next project', async (ctx) => { test('get the settings for a next project if a build system has no commands and overrides', async (ctx) => { const fixture = await createFixture('next-project', ctx) - const project = new Project(ctx.fs, fixture.cwd) + const project = new Project(ctx.fs, fixture.cwd).setNodeVersion('18.0.0') project.buildSystems = [new Bazel(project)] const settings = await project.getBuildSettings() @@ -47,8 +46,7 @@ test('get the settings for a next project if a build system has no commands and dist: '.next', env: {}, frameworkPort: 3000, - plugins_recommended: [], - plugins_from_config_file: [], + plugins: [{ alwaysInstall: true, name: '@netlify/plugin-nextjs' }], pollingStrategies: ['TCP'], }), ]) diff --git a/packages/build-info/src/settings/get-build-settings.ts b/packages/build-info/src/settings/get-build-settings.ts index 9b92638cf1..106875dca8 100644 --- a/packages/build-info/src/settings/get-build-settings.ts +++ b/packages/build-info/src/settings/get-build-settings.ts @@ -1,4 +1,4 @@ -import { type Framework } from '../frameworks/framework.js' +import { BuildPlugin, type Framework } from '../frameworks/framework.js' import { type Project } from '../project.js' export type Settings = { @@ -24,10 +24,8 @@ export type Settings = { /** The dist directory that contains the build output */ dist: string env: Record - /** Plugins installed via the netlify.toml */ - plugins_from_config_file: string[] /** Plugins that are detected via the framework detection and therefore recommended */ - plugins_recommended: string[] + plugins: BuildPlugin[] pollingStrategies: string[] /** The baseDirectory for the UI to configure (used to run the command in this working directory) */ baseDirectory?: string @@ -91,8 +89,7 @@ export async function getSettings(framework: Framework, project: Project, baseDi frameworkPort: framework.dev?.port, dist: project.fs.join(baseDirectory, framework.build.directory), env: framework.env || {}, - plugins_from_config_file: [], - plugins_recommended: framework.plugins || [], + plugins: framework.plugins || [], framework: { id: framework.id, name: framework.name, diff --git a/packages/build-info/src/settings/get-toml-settings.test.ts b/packages/build-info/src/settings/get-toml-settings.test.ts index 83dedb9aa8..73e968b7bc 100644 --- a/packages/build-info/src/settings/get-toml-settings.test.ts +++ b/packages/build-info/src/settings/get-toml-settings.test.ts @@ -107,7 +107,7 @@ package = "@netlify/plugin-nextjs" dist: '.next', frameworkPort: 3000, functionsDir: 'api', - plugins_from_config_file: ['@netlify/plugin-nextjs'], + plugins: [{ name: '@netlify/plugin-nextjs', source: 'toml' }], }), ) }) diff --git a/packages/build-info/src/settings/get-toml-settings.ts b/packages/build-info/src/settings/get-toml-settings.ts index 240e0f7063..f2737be989 100644 --- a/packages/build-info/src/settings/get-toml-settings.ts +++ b/packages/build-info/src/settings/get-toml-settings.ts @@ -31,17 +31,22 @@ export async function getTomlSettingsFromPath( const tomlFilePath = fs.join(directory, 'netlify.toml') try { - const settings: Partial = {} + const settings: Partial & Pick = { + plugins: [], + } const { build, dev, functions, template, plugins } = gracefulParseToml(await fs.readFile(tomlFilePath)) settings.buildCommand = build?.command ?? settings.buildCommand settings.dist = build?.publish ?? settings.dist settings.devCommand = dev?.command ?? settings.devCommand settings.frameworkPort = dev?.port ?? settings.frameworkPort - settings.plugins_from_config_file = plugins?.map((p) => p.package) ?? settings.plugins_from_config_file settings.functionsDir = (build?.functions || functions?.directory) ?? settings.functionsDir settings.template = template ?? settings.template + for (const plugin of plugins || []) { + settings.plugins.push({ name: plugin.package, source: 'toml' }) + } + return settings } catch { // no toml found or issue while parsing it diff --git a/packages/build-info/tests/__snapshots__/bin.test.ts.snap b/packages/build-info/tests/__snapshots__/bin.test.ts.snap index 237e5a1453..e4f4f76d7c 100644 --- a/packages/build-info/tests/__snapshots__/bin.test.ts.snap +++ b/packages/build-info/tests/__snapshots__/bin.test.ts.snap @@ -6,9 +6,10 @@ exports[`CLI --help flag 1`] = ` Print relevant build information from a project. Options: - --help Show help [boolean] - --version Show version number [boolean] - --rootDir The root directory of the project if different from projectDir - [string] - --featureFlags comma separated list of feature flags [string]" + --help Show help [boolean] + --version Show version number [boolean] + --rootDir The root directory of the project if different from proj + ectDir [string] + --featureFlags, --ff JSON stringified list of feature flags with values + [string]" `; From d50540330900cb34d2f8901fbdb320774d931fb2 Mon Sep 17 00:00:00 2001 From: Lukas Holzer Date: Mon, 18 Dec 2023 11:10:42 +0100 Subject: [PATCH 2/4] chore: update docs on the alwaysInstall --- packages/build-info/src/frameworks/framework.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/build-info/src/frameworks/framework.ts b/packages/build-info/src/frameworks/framework.ts index 396ab888ae..a72b08b139 100644 --- a/packages/build-info/src/frameworks/framework.ts +++ b/packages/build-info/src/frameworks/framework.ts @@ -41,7 +41,13 @@ export type FrameworkInfo = ReturnType export type BuildPlugin = { name: string - /** Plugins that should be always installed */ + /** + * This setting is for runtimes that are expected to be "automatically" + * installed. Even though they can be installed on package/toml, we always + * want them installed in the site settings. When installed our build will + * automatically install the latest version without the need of the user + * managing the version plugin. + */ alwaysInstall?: boolean source?: 'toml' } From 5b302adacfdcf89de1c0206e286cbdcaf5714cfc Mon Sep 17 00:00:00 2001 From: Lukas Holzer Date: Mon, 18 Dec 2023 11:13:28 +0100 Subject: [PATCH 3/4] chore: rename to autoInstall --- packages/build-info/src/build-systems/nx.test.ts | 2 +- packages/build-info/src/frameworks/framework.ts | 2 +- packages/build-info/src/frameworks/next.test.ts | 14 +++++++------- packages/build-info/src/frameworks/next.ts | 4 ++-- .../node/__snapshots__/get-build-info.test.ts.snap | 4 ++-- .../src/settings/get-build-settings.test.ts | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/build-info/src/build-systems/nx.test.ts b/packages/build-info/src/build-systems/nx.test.ts index 6f2b6f284b..1c98e350af 100644 --- a/packages/build-info/src/build-systems/nx.test.ts +++ b/packages/build-info/src/build-systems/nx.test.ts @@ -197,7 +197,7 @@ describe('nx-integrated project.json based', () => { frameworkPort: 4200, name: `Nx + Next.js ${join('packages/website')}`, packagePath: join('packages/website'), - plugins: [{ name: '@netlify/plugin-nextjs', alwaysInstall: true }], + plugins: [{ name: '@netlify/plugin-nextjs', autoInstall: true }], }), ]), ) diff --git a/packages/build-info/src/frameworks/framework.ts b/packages/build-info/src/frameworks/framework.ts index a72b08b139..196b197764 100644 --- a/packages/build-info/src/frameworks/framework.ts +++ b/packages/build-info/src/frameworks/framework.ts @@ -48,7 +48,7 @@ export type BuildPlugin = { * automatically install the latest version without the need of the user * managing the version plugin. */ - alwaysInstall?: boolean + autoInstall?: boolean source?: 'toml' } diff --git a/packages/build-info/src/frameworks/next.test.ts b/packages/build-info/src/frameworks/next.test.ts index e4dafe3eca..f4dc75f56a 100644 --- a/packages/build-info/src/frameworks/next.test.ts +++ b/packages/build-info/src/frameworks/next.test.ts @@ -38,7 +38,7 @@ describe('Next.js Plugin', () => { const project = new Project(fs, cwd).setNodeVersion('v10.13.0') const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) }) test('Should use the old runtime if the next.js version is not >= 13.5.0', async ({ fs, cwd }) => { @@ -46,7 +46,7 @@ describe('Next.js Plugin', () => { project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime' } const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) }) test('Should not detect Next.js plugin for Next.js if when Node version < 10.13.0', async ({ fs, cwd }) => { @@ -83,7 +83,7 @@ describe('New Next.js Runtime', () => { project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime@latest' } const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) }) test('Should use the old runtime if the next.js version is not >= 13.5.0', async ({ fs, cwd }) => { @@ -91,7 +91,7 @@ describe('New Next.js Runtime', () => { project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime@latest' } const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/next-runtime@latest', alwaysInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/next-runtime@latest', autoInstall: true }]) }) }) @@ -136,7 +136,7 @@ describe('simple Next.js project', async () => { test('Should detect Next.js plugin for Next.js if when Node version >= 10.13.0', async ({ fs, cwd }) => { const detected = await new Project(fs, cwd).setEnvironment({ NODE_VERSION: '18.x' }).detectFrameworks() expect(detected?.[0].id).toBe('next') - expect(detected?.[0].plugins).toMatchObject([{ name: '@netlify/plugin-nextjs', alwaysInstall: true }]) + expect(detected?.[0].plugins).toMatchObject([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) }) }) @@ -180,7 +180,7 @@ describe('Nx monorepo', () => { devCommand: 'nx run website:serve', dist: join('dist/packages/website'), frameworkPort: 4200, - plugins: [{ name: '@netlify/plugin-nextjs', alwaysInstall: true }], + plugins: [{ name: '@netlify/plugin-nextjs', autoInstall: true }], }) }) }) @@ -198,7 +198,7 @@ describe('Nx turborepo', () => { devCommand: 'turbo run dev --filter web', dist: join('apps/web/.next'), frameworkPort: 3000, - plugins: [{ name: '@netlify/plugin-nextjs', alwaysInstall: true }], + plugins: [{ name: '@netlify/plugin-nextjs', autoInstall: true }], }) }) }) diff --git a/packages/build-info/src/frameworks/next.ts b/packages/build-info/src/frameworks/next.ts index bbac82e1e2..fe4db2ab95 100644 --- a/packages/build-info/src/frameworks/next.ts +++ b/packages/build-info/src/frameworks/next.ts @@ -40,9 +40,9 @@ export class Next extends BaseFramework implements Framework { gte(this.detected.package.version, '13.5.0') && typeof runtimeFromRollout === 'string' ) { - this.plugins.push({ name: runtimeFromRollout ?? '@netlify/plugin-nextjs', alwaysInstall: true }) + this.plugins.push({ name: runtimeFromRollout ?? '@netlify/plugin-nextjs', autoInstall: true }) } else if (nodeVersion && gte(nodeVersion, '10.13.0')) { - this.plugins.push({ name: '@netlify/plugin-nextjs', alwaysInstall: true }) + this.plugins.push({ name: '@netlify/plugin-nextjs', autoInstall: true }) } return this as DetectedFramework } diff --git a/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap b/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap index 867e432206..bba0b2d2c0 100644 --- a/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap +++ b/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap @@ -85,7 +85,7 @@ exports[`should retrieve the build info for providing a rootDir 1`] = ` "packagePath": "packages/website", "plugins": [ { - "alwaysInstall": true, + "autoInstall": true, "name": "@netlify/plugin-nextjs", }, ], @@ -295,7 +295,7 @@ exports[`should retrieve the build info for providing a rootDir and the same pro "packagePath": "packages/website", "plugins": [ { - "alwaysInstall": true, + "autoInstall": true, "name": "@netlify/plugin-nextjs", }, ], diff --git a/packages/build-info/src/settings/get-build-settings.test.ts b/packages/build-info/src/settings/get-build-settings.test.ts index d99d5c7cea..9a21d1fff9 100644 --- a/packages/build-info/src/settings/get-build-settings.test.ts +++ b/packages/build-info/src/settings/get-build-settings.test.ts @@ -27,7 +27,7 @@ test('get the settings for a next project', async (ctx) => { dist: '.next', env: {}, frameworkPort: 3000, - plugins: [{ alwaysInstall: true, name: '@netlify/plugin-nextjs' }], + plugins: [{ autoInstall: true, name: '@netlify/plugin-nextjs' }], pollingStrategies: ['TCP'], }), ]) @@ -46,7 +46,7 @@ test('get the settings for a next project if a build system has no commands and dist: '.next', env: {}, frameworkPort: 3000, - plugins: [{ alwaysInstall: true, name: '@netlify/plugin-nextjs' }], + plugins: [{ autoInstall: true, name: '@netlify/plugin-nextjs' }], pollingStrategies: ['TCP'], }), ]) From 4302c0e8544a65031f3871d5c8b10d20d0860937 Mon Sep 17 00:00:00 2001 From: Lukas Holzer Date: Tue, 9 Jan 2024 13:45:08 +0100 Subject: [PATCH 4/4] chore: rename to package to comply with netlify toml version --- packages/build-info/src/build-systems/nx.test.ts | 2 +- packages/build-info/src/frameworks/angular.test.ts | 2 +- packages/build-info/src/frameworks/angular.ts | 2 +- packages/build-info/src/frameworks/framework.ts | 6 +++--- packages/build-info/src/frameworks/gatsby.test.ts | 2 +- packages/build-info/src/frameworks/gatsby.ts | 2 +- packages/build-info/src/frameworks/next.test.ts | 14 +++++++------- packages/build-info/src/frameworks/next.ts | 4 ++-- .../node/__snapshots__/get-build-info.test.ts.snap | 4 ++-- .../src/settings/get-build-settings.test.ts | 4 ++-- .../src/settings/get-toml-settings.test.ts | 2 +- .../build-info/src/settings/get-toml-settings.ts | 2 +- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/build-info/src/build-systems/nx.test.ts b/packages/build-info/src/build-systems/nx.test.ts index 1c98e350af..85466e38a1 100644 --- a/packages/build-info/src/build-systems/nx.test.ts +++ b/packages/build-info/src/build-systems/nx.test.ts @@ -197,7 +197,7 @@ describe('nx-integrated project.json based', () => { frameworkPort: 4200, name: `Nx + Next.js ${join('packages/website')}`, packagePath: join('packages/website'), - plugins: [{ name: '@netlify/plugin-nextjs', autoInstall: true }], + plugins: [{ package: '@netlify/plugin-nextjs', autoInstall: true }], }), ]), ) diff --git a/packages/build-info/src/frameworks/angular.test.ts b/packages/build-info/src/frameworks/angular.test.ts index 6b0fc0c393..e85247a460 100644 --- a/packages/build-info/src/frameworks/angular.test.ts +++ b/packages/build-info/src/frameworks/angular.test.ts @@ -32,7 +32,7 @@ test('should detect Angular', async ({ fs }) => { expect(detected?.[0].build.command).toBe('ng build --prod') expect(detected?.[0].build.directory).toBe(fs.join('dist', 'demo', 'browser')) expect(detected?.[0].dev?.command).toBe('ng serve') - expect(detected?.[0].plugins).toEqual([{ name: '@netlify/angular-runtime' }]) + expect(detected?.[0].plugins).toEqual([{ package: '@netlify/angular-runtime' }]) }) test('should set publish directory based on builder', async ({ fs }) => { diff --git a/packages/build-info/src/frameworks/angular.ts b/packages/build-info/src/frameworks/angular.ts index e8fe359406..33505951c5 100644 --- a/packages/build-info/src/frameworks/angular.ts +++ b/packages/build-info/src/frameworks/angular.ts @@ -31,7 +31,7 @@ export class Angular extends BaseFramework implements Framework { if (this.detected) { if (this.version && gte(this.version, '17.0.0-rc')) { - this.plugins.push({ name: '@netlify/angular-runtime' }) + this.plugins.push({ package: '@netlify/angular-runtime' }) const angularJson = await this.project.fs.gracefullyReadFile('angular.json') if (angularJson) { const { projects, defaultProject } = JSON.parse(angularJson) diff --git a/packages/build-info/src/frameworks/framework.ts b/packages/build-info/src/frameworks/framework.ts index 196b197764..099db454cc 100644 --- a/packages/build-info/src/frameworks/framework.ts +++ b/packages/build-info/src/frameworks/framework.ts @@ -40,7 +40,7 @@ export type Detection = { export type FrameworkInfo = ReturnType export type BuildPlugin = { - name: string + package: string /** * This setting is for runtimes that are expected to be "automatically" * installed. Even though they can be installed on package/toml, we always @@ -106,7 +106,7 @@ export interface Framework { staticAssetsDirectory?: string env: Record logo?: Record - plugins: string[] + plugins: BuildPlugin[] } } @@ -368,7 +368,7 @@ export abstract class BaseFramework implements Framework { {}, ) : undefined, - plugins: this.plugins.map(({ name }) => name), + plugins: this.plugins, } } } diff --git a/packages/build-info/src/frameworks/gatsby.test.ts b/packages/build-info/src/frameworks/gatsby.test.ts index 38b0f35df5..ffd9020702 100644 --- a/packages/build-info/src/frameworks/gatsby.test.ts +++ b/packages/build-info/src/frameworks/gatsby.test.ts @@ -27,7 +27,7 @@ test('should detect a simple Gatsby project and add the plugin if the node versi fs.cwd = cwd const detected = await new Project(fs, cwd).setNodeVersion('12.13.0').detectFrameworks() expect(detected?.[0].id).toBe('gatsby') - expect(detected?.[0].plugins).toMatchObject([{ name: '@netlify/plugin-gatsby' }]) + expect(detected?.[0].plugins).toMatchObject([{ package: '@netlify/plugin-gatsby' }]) }) test('should detect a simple Gatsby 4 project', async ({ fs }) => { diff --git a/packages/build-info/src/frameworks/gatsby.ts b/packages/build-info/src/frameworks/gatsby.ts index 745563ace9..eca06c7b50 100644 --- a/packages/build-info/src/frameworks/gatsby.ts +++ b/packages/build-info/src/frameworks/gatsby.ts @@ -45,7 +45,7 @@ export class Gatsby extends BaseFramework implements Framework { const nodeVersion = await this.project.getCurrentNodeVersion() if (nodeVersion && gte(nodeVersion, '12.13.0')) { - this.plugins.push({ name: '@netlify/plugin-gatsby' }) + this.plugins.push({ package: '@netlify/plugin-gatsby' }) } return this as DetectedFramework } diff --git a/packages/build-info/src/frameworks/next.test.ts b/packages/build-info/src/frameworks/next.test.ts index f4dc75f56a..7ccff9c64e 100644 --- a/packages/build-info/src/frameworks/next.test.ts +++ b/packages/build-info/src/frameworks/next.test.ts @@ -38,7 +38,7 @@ describe('Next.js Plugin', () => { const project = new Project(fs, cwd).setNodeVersion('v10.13.0') const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ package: '@netlify/plugin-nextjs', autoInstall: true }]) }) test('Should use the old runtime if the next.js version is not >= 13.5.0', async ({ fs, cwd }) => { @@ -46,7 +46,7 @@ describe('Next.js Plugin', () => { project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime' } const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ package: '@netlify/plugin-nextjs', autoInstall: true }]) }) test('Should not detect Next.js plugin for Next.js if when Node version < 10.13.0', async ({ fs, cwd }) => { @@ -83,7 +83,7 @@ describe('New Next.js Runtime', () => { project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime@latest' } const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ package: '@netlify/plugin-nextjs', autoInstall: true }]) }) test('Should use the old runtime if the next.js version is not >= 13.5.0', async ({ fs, cwd }) => { @@ -91,7 +91,7 @@ describe('New Next.js Runtime', () => { project.featureFlags = { project_ceruledge_ui: '@netlify/next-runtime@latest' } const frameworks = await project.detectFrameworks() expect(frameworks?.[0].id).toBe('next') - expect(frameworks?.[0].plugins).toEqual([{ name: '@netlify/next-runtime@latest', autoInstall: true }]) + expect(frameworks?.[0].plugins).toEqual([{ package: '@netlify/next-runtime@latest', autoInstall: true }]) }) }) @@ -136,7 +136,7 @@ describe('simple Next.js project', async () => { test('Should detect Next.js plugin for Next.js if when Node version >= 10.13.0', async ({ fs, cwd }) => { const detected = await new Project(fs, cwd).setEnvironment({ NODE_VERSION: '18.x' }).detectFrameworks() expect(detected?.[0].id).toBe('next') - expect(detected?.[0].plugins).toMatchObject([{ name: '@netlify/plugin-nextjs', autoInstall: true }]) + expect(detected?.[0].plugins).toMatchObject([{ package: '@netlify/plugin-nextjs', autoInstall: true }]) }) }) @@ -180,7 +180,7 @@ describe('Nx monorepo', () => { devCommand: 'nx run website:serve', dist: join('dist/packages/website'), frameworkPort: 4200, - plugins: [{ name: '@netlify/plugin-nextjs', autoInstall: true }], + plugins: [{ package: '@netlify/plugin-nextjs', autoInstall: true }], }) }) }) @@ -198,7 +198,7 @@ describe('Nx turborepo', () => { devCommand: 'turbo run dev --filter web', dist: join('apps/web/.next'), frameworkPort: 3000, - plugins: [{ name: '@netlify/plugin-nextjs', autoInstall: true }], + plugins: [{ package: '@netlify/plugin-nextjs', autoInstall: true }], }) }) }) diff --git a/packages/build-info/src/frameworks/next.ts b/packages/build-info/src/frameworks/next.ts index fe4db2ab95..eb668a8abb 100644 --- a/packages/build-info/src/frameworks/next.ts +++ b/packages/build-info/src/frameworks/next.ts @@ -40,9 +40,9 @@ export class Next extends BaseFramework implements Framework { gte(this.detected.package.version, '13.5.0') && typeof runtimeFromRollout === 'string' ) { - this.plugins.push({ name: runtimeFromRollout ?? '@netlify/plugin-nextjs', autoInstall: true }) + this.plugins.push({ package: runtimeFromRollout ?? '@netlify/plugin-nextjs', autoInstall: true }) } else if (nodeVersion && gte(nodeVersion, '10.13.0')) { - this.plugins.push({ name: '@netlify/plugin-nextjs', autoInstall: true }) + this.plugins.push({ package: '@netlify/plugin-nextjs', autoInstall: true }) } return this as DetectedFramework } diff --git a/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap b/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap index bba0b2d2c0..de97a07335 100644 --- a/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap +++ b/packages/build-info/src/node/__snapshots__/get-build-info.test.ts.snap @@ -86,7 +86,7 @@ exports[`should retrieve the build info for providing a rootDir 1`] = ` "plugins": [ { "autoInstall": true, - "name": "@netlify/plugin-nextjs", + "package": "@netlify/plugin-nextjs", }, ], "pollingStrategies": [ @@ -296,7 +296,7 @@ exports[`should retrieve the build info for providing a rootDir and the same pro "plugins": [ { "autoInstall": true, - "name": "@netlify/plugin-nextjs", + "package": "@netlify/plugin-nextjs", }, ], "pollingStrategies": [ diff --git a/packages/build-info/src/settings/get-build-settings.test.ts b/packages/build-info/src/settings/get-build-settings.test.ts index 9a21d1fff9..51684d6b1b 100644 --- a/packages/build-info/src/settings/get-build-settings.test.ts +++ b/packages/build-info/src/settings/get-build-settings.test.ts @@ -27,7 +27,7 @@ test('get the settings for a next project', async (ctx) => { dist: '.next', env: {}, frameworkPort: 3000, - plugins: [{ autoInstall: true, name: '@netlify/plugin-nextjs' }], + plugins: [{ autoInstall: true, package: '@netlify/plugin-nextjs' }], pollingStrategies: ['TCP'], }), ]) @@ -46,7 +46,7 @@ test('get the settings for a next project if a build system has no commands and dist: '.next', env: {}, frameworkPort: 3000, - plugins: [{ autoInstall: true, name: '@netlify/plugin-nextjs' }], + plugins: [{ autoInstall: true, package: '@netlify/plugin-nextjs' }], pollingStrategies: ['TCP'], }), ]) diff --git a/packages/build-info/src/settings/get-toml-settings.test.ts b/packages/build-info/src/settings/get-toml-settings.test.ts index 73e968b7bc..ce07bd30fe 100644 --- a/packages/build-info/src/settings/get-toml-settings.test.ts +++ b/packages/build-info/src/settings/get-toml-settings.test.ts @@ -107,7 +107,7 @@ package = "@netlify/plugin-nextjs" dist: '.next', frameworkPort: 3000, functionsDir: 'api', - plugins: [{ name: '@netlify/plugin-nextjs', source: 'toml' }], + plugins: [{ package: '@netlify/plugin-nextjs', source: 'toml' }], }), ) }) diff --git a/packages/build-info/src/settings/get-toml-settings.ts b/packages/build-info/src/settings/get-toml-settings.ts index f2737be989..b20d310e26 100644 --- a/packages/build-info/src/settings/get-toml-settings.ts +++ b/packages/build-info/src/settings/get-toml-settings.ts @@ -44,7 +44,7 @@ export async function getTomlSettingsFromPath( settings.template = template ?? settings.template for (const plugin of plugins || []) { - settings.plugins.push({ name: plugin.package, source: 'toml' }) + settings.plugins.push({ package: plugin.package, source: 'toml' }) } return settings