diff --git a/src/commands/completion/completion.ts b/src/commands/completion/completion.ts index e90b5550baf..2f0f8a7de3a 100644 --- a/src/commands/completion/completion.ts +++ b/src/commands/completion/completion.ts @@ -5,7 +5,7 @@ import { fileURLToPath } from 'url' import inquirer from 'inquirer' import type { OptionValues } from 'commander' -import { install, uninstall } from '@pnpm/tabtab' +import { install, isShellSupported, uninstall } from '@pnpm/tabtab' import { generateAutocompletion } from '../../lib/completion/index.js' import { @@ -27,10 +27,19 @@ export const completionGenerate = async (_options: OptionValues, command: BaseCo return logAndThrowError(`There has been an error generating the completion script.`) } + let shell: 'bash' | 'fish' | 'pwsh' | 'zsh' | undefined + if (typeof _options.shell === 'string') { + if (!isShellSupported(_options.shell)) { + return logAndThrowError(`Unsupported shell "${_options.shell}". Supported shells are bash, fish, pwsh, and zsh.`) + } + shell = _options.shell + } + generateAutocompletion(parent) await install({ name: parent.name(), completer, + shell, }) const completionScriptPath = join(homedir(), `.config/tabtab/${parent.name()}.zsh`) diff --git a/src/commands/completion/index.ts b/src/commands/completion/index.ts index 367e1823cc5..6adb2c686ae 100644 --- a/src/commands/completion/index.ts +++ b/src/commands/completion/index.ts @@ -7,6 +7,7 @@ export const createCompletionCommand = (program: BaseCommand) => { .command('completion:install') .alias('completion:generate') .description('Generates completion script for your preferred shell') + .option('--shell ', 'Shell to install completion for (bash, fish, pwsh, zsh)') .action(async (options: OptionValues, command: BaseCommand) => { const { completionGenerate } = await import('./completion.js') await completionGenerate(options, command) diff --git a/src/utils/telemetry/report-error.ts b/src/utils/telemetry/report-error.ts index c14b03ee1cc..a77f2f2a524 100644 --- a/src/utils/telemetry/report-error.ts +++ b/src/utils/telemetry/report-error.ts @@ -22,7 +22,7 @@ const dirPath = dirname(fileURLToPath(import.meta.url)) */ // @ts-expect-error TS(7006) FIXME: Parameter 'error' implicitly has an 'any' type. export const reportError = async function (error, config = {}) { - if (isCI) { + if (isCI || process.env.CI) { return } // convert a NotifiableError to an error class diff --git a/tests/integration/commands/completion/completion-install.test.ts b/tests/integration/commands/completion/completion-install.test.ts index 00572999ea9..cf853bc7de6 100644 --- a/tests/integration/commands/completion/completion-install.test.ts +++ b/tests/integration/commands/completion/completion-install.test.ts @@ -1,7 +1,7 @@ import { describe, test, beforeAll, afterAll } from 'vitest' import fs from 'fs' import { rm } from 'fs/promises' -import { handleQuestions, CONFIRM, DOWN, NO, answerWithValue } from '../../utils/handle-questions.js' +import { handleQuestions, CONFIRM, NO } from '../../utils/handle-questions.js' import execa from 'execa' import { cliPath } from '../../utils/cli-path.js' import { join } from 'path' @@ -27,13 +27,9 @@ describe('completion:install command', () => { 'should add compinit to .zshrc when user confirms prompt', async ({ expect }) => { fs.writeFileSync(zshConfigPath, TABTAB_CONFIG_LINE) - const childProcess = execa(cliPath, ['completion:install'], options) + const childProcess = execa(cliPath, ['completion:install', '--shell', 'zsh'], options) handleQuestions(childProcess, [ - { - question: 'Which Shell do you use ?', - answer: answerWithValue(DOWN), - }, { question: 'We will install completion to ~/.zshrc, is it ok ?', answer: CONFIRM, @@ -54,20 +50,16 @@ describe('completion:install command', () => { 'should not add compinit to .zshrc when user does not confirm prompt', async ({ expect }) => { fs.writeFileSync(zshConfigPath, TABTAB_CONFIG_LINE) - const childProcess = execa(cliPath, ['completion:install'], options) + const childProcess = execa(cliPath, ['completion:install', '--shell', 'zsh'], options) handleQuestions(childProcess, [ - { - question: 'Which Shell do you use ?', - answer: answerWithValue(DOWN), - }, { question: 'We will install completion to ~/.zshrc, is it ok ?', answer: CONFIRM, }, { question: 'Would you like to add it?', - answer: answerWithValue(NO), + answer: [NO, CONFIRM], }, ]) diff --git a/tests/integration/commands/dev/dev.test.ts b/tests/integration/commands/dev/dev.test.ts index c1ca169d281..20cd2347e32 100644 --- a/tests/integration/commands/dev/dev.test.ts +++ b/tests/integration/commands/dev/dev.test.ts @@ -828,13 +828,15 @@ describe.concurrent('command/dev', () => { test('deploy environment variables injected by onDev plugin hooks are injected into functions', async (t) => { await withSiteBuilder(t, async (builder) => { + const targetPort = await getPort() + await builder .withNetlifyToml({ config: { plugins: [{ package: './plugins/plugin' }], dev: { command: 'node index.mjs', - targetPort: 4445, + targetPort, }, }, }) @@ -889,7 +891,7 @@ describe.concurrent('command/dev', () => { res.end(); }) - server.listen(4445) + server.listen(${targetPort.toString()}) `, }) .build() diff --git a/tests/integration/commands/dev/redirects.test.ts b/tests/integration/commands/dev/redirects.test.ts index 19b8d48d511..cbd0b4a6171 100644 --- a/tests/integration/commands/dev/redirects.test.ts +++ b/tests/integration/commands/dev/redirects.test.ts @@ -1,3 +1,6 @@ +import { readFile, writeFile } from 'fs/promises' +import { join } from 'path' + import getPort from 'get-port' import fetch from 'node-fetch' import { describe, expect, test } from 'vitest' @@ -32,27 +35,46 @@ describe('redirects', async () => { }) }) - await setupFixtureTests('next-app', { devServer: { env: { NETLIFY_DEV_SERVER_CHECK_SSG_ENDPOINTS: 1 } } }, () => { - test('should prefer local files instead of redirect when not forced', async ({ devServer }) => { - const response = await fetch(`http://localhost:${devServer!.port}/test.txt`, {}) - - expect(response.status).toBe(200) - - const result = await response.text() - expect(result.trim()).toEqual('hello world') - }) - - test('should check for the dynamic page existence before doing redirect', async ({ - devServer, - }) => { - const response = await fetch(`http://localhost:${devServer!.port}/`, {}) - - expect(response.status).toBe(200) - - const result = await response.text() - expect(result.toLowerCase()).not.toContain('netlify') - }) - }) + await setupFixtureTests( + 'next-app', + { + devServer: { env: { NETLIFY_DEV_SERVER_CHECK_SSG_ENDPOINTS: 1 } }, + setup: async ({ fixture }) => { + const targetPort = await getPort() + const packageJsonPath = join(fixture.directory, 'package.json') + const netlifyTomlPath = join(fixture.directory, 'netlify.toml') + const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as { scripts: { dev: string } } + + packageJson.scripts.dev = `next dev -p ${targetPort.toString()}` + await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`) + await writeFile( + netlifyTomlPath, + (await readFile(netlifyTomlPath, 'utf8')).replace('targetPort = 6123', `targetPort = ${targetPort.toString()}`), + ) + }, + }, + () => { + test('should prefer local files instead of redirect when not forced', async ({ devServer }) => { + const response = await fetch(`http://localhost:${devServer!.port}/test.txt`, {}) + + expect(response.status).toBe(200) + + const result = await response.text() + expect(result.trim()).toEqual('hello world') + }) + + test('should check for the dynamic page existence before doing redirect', async ({ + devServer, + }) => { + const response = await fetch(`http://localhost:${devServer!.port}/`, {}) + + expect(response.status).toBe(200) + + const result = await response.text() + expect(result.toLowerCase()).not.toContain('netlify') + }) + }, + ) test('should not check the endpoint existence for hidden proxies', async (t) => { await withSiteBuilder(t, async (builder) => { diff --git a/tests/integration/commands/help/__snapshots__/help.test.ts.snap b/tests/integration/commands/help/__snapshots__/help.test.ts.snap index e80e107910c..314defe15ca 100644 --- a/tests/integration/commands/help/__snapshots__/help.test.ts.snap +++ b/tests/integration/commands/help/__snapshots__/help.test.ts.snap @@ -59,10 +59,10 @@ USAGE $ netlify completion [options] OPTIONS - -h, --help display help for command --debug Print debugging information --auth Netlify auth token - can be used to run this command without logging in + -h, --help display help for command DESCRIPTION Run this command to see instructions for your shell.