From 5da2b2e1e37361f2f6ef80cc6a4317735bf82ac6 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 29 Nov 2023 11:01:45 +0100 Subject: [PATCH 1/9] refactor: typescriptify a bit --- src/commands/base-command.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/commands/base-command.ts b/src/commands/base-command.ts index 7a73b601ddc..a10d3af9409 100644 --- a/src/commands/base-command.ts +++ b/src/commands/base-command.ts @@ -38,6 +38,9 @@ import openBrowser from '../utils/open-browser.js' import StateConfig from '../utils/state-config.js' import { identify, reportError, track } from '../utils/telemetry/index.js' +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type $FIXME = any + // load the autocomplete plugin inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt) /** Netlify CLI client id. Lives in bot@netlify.com */ @@ -229,7 +232,7 @@ export default class BaseCommand extends Command { } debug(`${name}:preAction`)('start') this.analytics = { startTime: process.hrtime.bigint() } - await this.init(actionCommand) + await this.init(actionCommand as BaseCommand) debug(`${name}:preAction`)('end') }) } @@ -521,8 +524,7 @@ export default class BaseCommand extends Command { * @param {BaseCommand} actionCommand The command of the action that is run (`this.` gets the parent command) * @private */ - // @ts-expect-error TS(7006) FIXME: Parameter 'actionCommand' implicitly has an 'any' ... Remove this comment to see the full error message - async init(actionCommand) { + async init(actionCommand: C) { debug(`${actionCommand.name()}:init`)('start') const flags = actionCommand.opts() // here we actually want to use the process.cwd as we are setting the workingDir @@ -689,21 +691,19 @@ export default class BaseCommand extends Command { /** * Find and resolve the Netlify configuration - * @param {object} config - * @param {string} config.cwd - * @param {string|null=} config.token - * @param {*} config.state - * @param {boolean=} config.offline - * @param {string=} config.configFilePath An optional path to the netlify configuration file e.g. netlify.toml - * @param {string=} config.packagePath - * @param {string=} config.repositoryRoot - * @param {string=} config.host - * @param {string=} config.pathPrefix - * @param {string=} config.scheme - * @returns {ReturnType} */ - // @ts-expect-error TS(7023) FIXME: 'getConfig' implicitly has return type 'any' becau... Remove this comment to see the full error message - async getConfig(config) { + async getConfig(config: { + cwd: string + token: string | null + state: $FIXME + offline?: boolean + configFilePath?: string + packagePath?: string + repositoryRoot?: string + host?: string + pathPrefix?: string + scheme?: string + }): Promise> { // the flags that are passed to the command like `--debug` or `--offline` const flags = this.opts() From 97a14025171804bf3bb977acab23344b730942e4 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 29 Nov 2023 11:38:55 +0100 Subject: [PATCH 2/9] feat: inject Netlify CLI Version to build command --- src/commands/base-command.ts | 6 ++++-- src/utils/command-helpers.ts | 3 ++- .../integration/commands/build/build.test.js | 19 ++++++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/commands/base-command.ts b/src/commands/base-command.ts index a10d3af9409..02014944969 100644 --- a/src/commands/base-command.ts +++ b/src/commands/base-command.ts @@ -26,6 +26,7 @@ import { exit, getToken, log, + netlifyCliVersion, normalizeConfig, padLeft, pollForToken, @@ -608,7 +609,8 @@ export default class BaseCommand extends Command { token, ...apiUrlOpts, }) - const { buildDir, config, configPath, repositoryRoot, siteInfo } = cachedConfig + const { buildDir, config, configPath, env, repositoryRoot, siteInfo } = cachedConfig + env.NETLIFY_CLI_VERSION = { sources: ['internal'], value: netlifyCliVersion } const normalizedConfig = normalizeConfig(config) const agent = await getAgent({ httpProxy: flags.httpProxy, @@ -694,7 +696,7 @@ export default class BaseCommand extends Command { */ async getConfig(config: { cwd: string - token: string | null + token?: string | null state: $FIXME offline?: boolean configFilePath?: string diff --git a/src/utils/command-helpers.ts b/src/utils/command-helpers.ts index ee53421d7f8..e3e4f6d1f7b 100644 --- a/src/utils/command-helpers.ts +++ b/src/utils/command-helpers.ts @@ -50,7 +50,8 @@ const arch = os.arch() === 'ia32' ? 'x86' : os.arch() const { name, version } = await getPackageJson() -export const USER_AGENT = `${name}/${version} ${platform}-${arch} node-${process.version}` +export const netlifyCliVersion = version +export const USER_AGENT = `${name}/${netlifyCliVersion} ${platform}-${arch} node-${process.version}` /** A list of base command flags that needs to be sorted down on documentation and on help pages */ const BASE_FLAGS = new Set(['--debug', '--httpProxy', '--httpProxyCertificateFilename']) diff --git a/tests/integration/commands/build/build.test.js b/tests/integration/commands/build/build.test.js index 47d193bda91..8efb0fb41f6 100644 --- a/tests/integration/commands/build/build.test.js +++ b/tests/integration/commands/build/build.test.js @@ -38,7 +38,11 @@ const runBuildCommand = async function ( outputs = [outputs] } outputs.forEach((output) => { - t.expect(all.includes(output), `Output of build command does not include '${output}'`).toBe(true) + if (output instanceof RegExp) { + t.expect(all).toMatch(output) + } else { + t.expect(all.includes(output), `Output of build command does not include '${output}'`).toBe(true) + } }) t.expect(exitCode).toBe(expectedExitCode) } @@ -286,4 +290,17 @@ describe.concurrent('command/build', () => { }) }) }) + + test('should have version in NETLIFY_CLI_VERSION variable', async (t) => { + await withSiteBuilder('NETLIFY_CLI_VERSION-env', async (builder) => { + await builder + .withNetlifyToml({ config: { build: { command: 'echo NETLIFY_CLI_VERSION=$NETLIFY_CLI_VERSION' } } }) + .build() + + await runBuildCommand(t, builder.directory, { + output: /NETLIFY_CLI_VERSION=\d+\.\d+.\d+/, + flags: ['--offline'], + }) + }) + }) }) From ba8185498a2f3cd567a0227e03d5b0a44c913bfa Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 29 Nov 2023 12:00:24 +0100 Subject: [PATCH 3/9] chore: also test for ntl dev --- tests/integration/commands/dev/dev.config.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/integration/commands/dev/dev.config.test.js b/tests/integration/commands/dev/dev.config.test.js index f6a3b9f05e3..cc0a8cba5de 100644 --- a/tests/integration/commands/dev/dev.config.test.js +++ b/tests/integration/commands/dev/dev.config.test.js @@ -142,6 +142,17 @@ describe.concurrent('commands/dev/config', () => { }) }) + test('should provide CLI version in env var', async (t) => { + await withSiteBuilder('site-with-netlify-version-env-var', async (builder) => { + await builder.withNetlifyToml({ config: { dev: { command: `node -e console.log(process.env)` } } }).build() + + await withDevServer({ cwd: builder.directory }, async (server) => { + await server.close() + t.expect(server.output).toContain('NETLIFY_CLI_VERSION') + }) + }) + }) + test('should set value of the CONTEXT env variable', async (t) => { await withSiteBuilder('site-with-context-override', async (builder) => { builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ From 3f720b7641f86a7b2735a1f476828ae4d4fe6580 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 29 Nov 2023 13:55:00 +0100 Subject: [PATCH 4/9] fix: dont show internal variables in env:list --- src/commands/env/env-list.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands/env/env-list.ts b/src/commands/env/env-list.ts index 08b08a23a0a..856e0829a4c 100644 --- a/src/commands/env/env-list.ts +++ b/src/commands/env/env-list.ts @@ -61,8 +61,10 @@ export const envList = async (options: OptionValues, command: BaseCommand) => { // filter out general sources environment = Object.fromEntries( - // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. - Object.entries(environment).filter(([, variable]) => variable.sources[0] !== 'general'), + Object.entries(environment).filter( + // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'. + ([, variable]) => variable.sources[0] !== 'general' && variable.sources[0] !== 'internal', + ), ) // Return json response for piping commands From b0576c23eee7bb053612c570a3b8438715f3b0ce Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 13 Dec 2023 13:50:44 +0100 Subject: [PATCH 5/9] fix: prevent dev server from dying immediately --- tests/integration/commands/dev/dev.config.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/integration/commands/dev/dev.config.test.js b/tests/integration/commands/dev/dev.config.test.js index cc0a8cba5de..9db6dcbed63 100644 --- a/tests/integration/commands/dev/dev.config.test.js +++ b/tests/integration/commands/dev/dev.config.test.js @@ -144,7 +144,11 @@ describe.concurrent('commands/dev/config', () => { test('should provide CLI version in env var', async (t) => { await withSiteBuilder('site-with-netlify-version-env-var', async (builder) => { - await builder.withNetlifyToml({ config: { dev: { command: `node -e console.log(process.env)` } } }).build() + await builder + .withNetlifyToml({ + config: { dev: { command: `node -e console.log(process.env); setTimeout(undefined, 100)` } }, + }) + .build() await withDevServer({ cwd: builder.directory }, async (server) => { await server.close() From 1554fdeae6fde49a7516805c0b427b6da2d38a69 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 13 Dec 2023 13:51:39 +0100 Subject: [PATCH 6/9] fix: make it more apparenty why it's happening --- tests/integration/commands/dev/dev.config.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/integration/commands/dev/dev.config.test.js b/tests/integration/commands/dev/dev.config.test.js index 9db6dcbed63..936478db3f6 100644 --- a/tests/integration/commands/dev/dev.config.test.js +++ b/tests/integration/commands/dev/dev.config.test.js @@ -146,7 +146,11 @@ describe.concurrent('commands/dev/config', () => { await withSiteBuilder('site-with-netlify-version-env-var', async (builder) => { await builder .withNetlifyToml({ - config: { dev: { command: `node -e console.log(process.env); setTimeout(undefined, 100)` } }, + config: { + dev: { + command: `node -e console.log(process.env); setTimeout(() => "we need this to keep the dev server running", 100)`, + }, + }, }) .build() From 1b70e946381bb8517ee83bc8fe5176894a479964 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Thu, 14 Dec 2023 08:59:57 +0100 Subject: [PATCH 7/9] fix: maybe a longer-running process helps? --- tests/integration/commands/dev/dev.config.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/commands/dev/dev.config.test.js b/tests/integration/commands/dev/dev.config.test.js index 936478db3f6..b3cb9395812 100644 --- a/tests/integration/commands/dev/dev.config.test.js +++ b/tests/integration/commands/dev/dev.config.test.js @@ -148,7 +148,7 @@ describe.concurrent('commands/dev/config', () => { .withNetlifyToml({ config: { dev: { - command: `node -e console.log(process.env); setTimeout(() => "we need this to keep the dev server running", 100)`, + command: `node -e console.log(process.env); setInterval(() => "we need this to keep the dev server running", 100)`, }, }, }) From 283c00061d4a4462f91545e0535ddf1ccd814da4 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Thu, 21 Dec 2023 17:01:35 +0100 Subject: [PATCH 8/9] fix: rewrite test --- .../commands/dev/dev.config.test.js | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/integration/commands/dev/dev.config.test.js b/tests/integration/commands/dev/dev.config.test.js index b3cb9395812..768f6938e9c 100644 --- a/tests/integration/commands/dev/dev.config.test.js +++ b/tests/integration/commands/dev/dev.config.test.js @@ -145,18 +145,34 @@ describe.concurrent('commands/dev/config', () => { test('should provide CLI version in env var', async (t) => { await withSiteBuilder('site-with-netlify-version-env-var', async (builder) => { await builder + .withContentFile({ + content: ` + import http from "http"; + + http.createServer((req, res) => { + res.write(JSON.stringify({ + NETLIFY_CLI_VERSION: process.env.NETLIFY_CLI_VERSION, + })) + res.end() + }).listen(1234); + `, + path: 'devserver.mjs', + }) .withNetlifyToml({ config: { dev: { - command: `node -e console.log(process.env); setInterval(() => "we need this to keep the dev server running", 100)`, + framework: '#custom', + command: 'node devserver.mjs', + targetPort: 1234, }, }, }) .build() await withDevServer({ cwd: builder.directory }, async (server) => { - await server.close() - t.expect(server.output).toContain('NETLIFY_CLI_VERSION') + const resp = await fetch(server.url) + const { NETLIFY_CLI_VERSION } = await resp.json() + t.expect(NETLIFY_CLI_VERSION).toMatch(/\d+\.\d+\.\d+/) }) }) }) From db10c9aebfaa13ea8db8b2de5ae3c549ebcd63b2 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Thu, 21 Dec 2023 18:03:06 +0100 Subject: [PATCH 9/9] fix: add special case for windows syntax --- tests/integration/commands/build/build.test.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/integration/commands/build/build.test.js b/tests/integration/commands/build/build.test.js index 8efb0fb41f6..67971e64146 100644 --- a/tests/integration/commands/build/build.test.js +++ b/tests/integration/commands/build/build.test.js @@ -1,4 +1,5 @@ import path from 'path' +import process from 'process' import execa from 'execa' import { describe, test } from 'vitest' @@ -294,7 +295,16 @@ describe.concurrent('command/build', () => { test('should have version in NETLIFY_CLI_VERSION variable', async (t) => { await withSiteBuilder('NETLIFY_CLI_VERSION-env', async (builder) => { await builder - .withNetlifyToml({ config: { build: { command: 'echo NETLIFY_CLI_VERSION=$NETLIFY_CLI_VERSION' } } }) + .withNetlifyToml({ + config: { + build: { + command: + process.platform === 'win32' + ? 'echo NETLIFY_CLI_VERSION=%NETLIFY_CLI_VERSION%' + : 'echo NETLIFY_CLI_VERSION=$NETLIFY_CLI_VERSION', + }, + }, + }) .build() await runBuildCommand(t, builder.directory, {