diff --git a/out/cli.cjs b/out/cli.cjs index 18705920..1ecbdf5d 100755 --- a/out/cli.cjs +++ b/out/cli.cjs @@ -57238,7 +57238,9 @@ var PROVIDER_BILLING_URLS = { }; var InsufficientCreditsError = class extends Error { constructor(provider, message) { - super(message || `Insufficient credits or quota for provider '${provider}'`); + super( + message || `Insufficient credits or quota for provider '${provider}'` + ); this.name = "InsufficientCreditsError"; this.provider = provider; } @@ -57490,7 +57492,9 @@ ${source_default.red("\u2716")} ${source_default.bold.red(formatted.title)} `; if (formatted.helpUrl) { output += ` - ${source_default.cyan("Help:")} ${source_default.underline(formatted.helpUrl)} + ${source_default.cyan("Help:")} ${source_default.underline( + formatted.helpUrl + )} `; } if (formatted.suggestion) { @@ -67277,8 +67281,8 @@ var MLXEngine = class { var DeepseekEngine = class extends OpenAiEngine { constructor(config7) { super({ - ...config7, - baseURL: "https://api.deepseek.com/v1" + baseURL: "https://api.deepseek.com/v1", + ...config7 }); // Identical method from OpenAiEngine, re-implemented here this.generateCommitMessage = async (messages) => { @@ -67949,11 +67953,9 @@ var GenerateCommitMessageErrorEnum = ((GenerateCommitMessageErrorEnum2) => { return GenerateCommitMessageErrorEnum2; })(GenerateCommitMessageErrorEnum || {}); async function handleModelNotFoundError(error, provider, currentModel) { - console.log( - source_default.red(` + console.log(source_default.red(` \u2716 Model '${currentModel}' not found -`) - ); +`)); const suggestedModels = getSuggestedModels(provider, currentModel); const recommended = RECOMMENDED_MODELS[provider]; if (suggestedModels.length === 0) { @@ -68925,6 +68927,11 @@ var OTHER_PROVIDERS = [ "mlx" /* MLX */ ]; var NO_API_KEY_PROVIDERS = [ + "ollama" /* OLLAMA */, + "mlx" /* MLX */, + "test" /* TEST */ +]; +var MODEL_REQUIRED_PROVIDERS = [ "ollama" /* OLLAMA */, "mlx" /* MLX */ ]; @@ -69202,21 +69209,25 @@ async function runSetup() { }; setGlobalConfig(newConfig); ce( - `${source_default.green("\u2714")} Configuration saved to ~/.opencommit + `${source_default.green( + "\u2714" + )} Configuration saved to ~/.opencommit - Run ${source_default.cyan("oco")} to generate commit messages!` + Run ${source_default.cyan( + "oco" + )} to generate commit messages!` ); return true; } function isFirstRun() { - if (!getIsGlobalConfigFileExist()) { - return true; - } const config7 = getConfig(); const provider = config7.OCO_AI_PROVIDER || "openai" /* OPENAI */; - if (NO_API_KEY_PROVIDERS.includes(provider)) { + if (MODEL_REQUIRED_PROVIDERS.includes(provider)) { return !config7.OCO_MODEL; } + if (provider === "test" /* TEST */) { + return false; + } return !config7.OCO_API_KEY; } async function promptForMissingApiKey() { @@ -69229,11 +69240,9 @@ async function promptForMissingApiKey() { return true; } console.log( - source_default.yellow( - ` + source_default.yellow(` API key missing for ${provider}. Let's set it up. -` - ) +`) ); const apiKey = await getApiKey(provider); if (hD2(apiKey)) { @@ -69291,9 +69300,11 @@ async function listModels(provider, useCache = true) { const providerKey = provider.toLowerCase(); models = MODEL_LIST[providerKey] || []; } - console.log(` + console.log( + ` ${source_default.bold("Available models for")} ${source_default.cyan(provider)}: -`); +` + ); if (models.length === 0) { console.log(source_default.dim(" No models found")); } else { @@ -69313,12 +69324,21 @@ async function refreshModels(provider) { loadingSpinner.start(`Fetching models from ${provider}...`); clearModelCache(); try { - const models = await fetchModelsForProvider(provider, apiKey, void 0, true); + const models = await fetchModelsForProvider( + provider, + apiKey, + void 0, + true + ); loadingSpinner.stop(`${source_default.green("+")} Fetched ${models.length} models`); await listModels(provider, true); } catch (error) { loadingSpinner.stop(source_default.red("Failed to fetch models")); - console.error(source_default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`)); + console.error( + source_default.red( + `Error: ${error instanceof Error ? error.message : "Unknown error"}` + ) + ); } } var modelsCommand = G3( @@ -69348,7 +69368,9 @@ var modelsCommand = G3( const cacheInfo = getCacheInfo(); if (cacheInfo.timestamp) { console.log( - source_default.dim(` Cache last updated: ${formatCacheAge2(cacheInfo.timestamp)}`) + source_default.dim( + ` Cache last updated: ${formatCacheAge2(cacheInfo.timestamp)}` + ) ); if (cacheInfo.providers.length > 0) { console.log( @@ -69363,9 +69385,7 @@ var modelsCommand = G3( } else { await listModels(provider); } - ce( - `Run ${source_default.cyan("oco models --refresh")} to update the model list` - ); + ce(`Run ${source_default.cyan("oco models --refresh")} to update the model list`); } ); @@ -69561,7 +69581,13 @@ Z2( { version: package_default.version, name: "opencommit", - commands: [configCommand, hookCommand, commitlintConfigCommand, setupCommand, modelsCommand], + commands: [ + configCommand, + hookCommand, + commitlintConfigCommand, + setupCommand, + modelsCommand + ], flags: { fgm: { type: Boolean, @@ -69585,23 +69611,23 @@ Z2( help: { description: package_default.description } }, async ({ flags }) => { + if (await isHookCalled()) { + await prepareCommitMessageHook(); + return; + } await runMigrations(); await checkIsLatestVersion(); - if (await isHookCalled()) { - prepareCommitMessageHook(); - } else { - if (isFirstRun()) { - const setupComplete = await runSetup(); - if (!setupComplete) { - process.exit(1); - } - } - const hasApiKey = await promptForMissingApiKey(); - if (!hasApiKey) { + if (isFirstRun()) { + const setupComplete = await runSetup(); + if (!setupComplete) { process.exit(1); } - commit(extraArgs, flags.context, false, flags.fgm, flags.yes); } + const hasApiKey = await promptForMissingApiKey(); + if (!hasApiKey) { + process.exit(1); + } + commit(extraArgs, flags.context, false, flags.fgm, flags.yes); }, extraArgs ); diff --git a/out/github-action.cjs b/out/github-action.cjs index 18880619..e1d13eaf 100644 --- a/out/github-action.cjs +++ b/out/github-action.cjs @@ -78216,7 +78216,9 @@ var PROVIDER_BILLING_URLS = { }; var InsufficientCreditsError = class extends Error { constructor(provider, message) { - super(message || `Insufficient credits or quota for provider '${provider}'`); + super( + message || `Insufficient credits or quota for provider '${provider}'` + ); this.name = "InsufficientCreditsError"; this.provider = provider; } @@ -88062,8 +88064,8 @@ var MLXEngine = class { var DeepseekEngine = class extends OpenAiEngine { constructor(config6) { super({ - ...config6, - baseURL: "https://api.deepseek.com/v1" + baseURL: "https://api.deepseek.com/v1", + ...config6 }); // Identical method from OpenAiEngine, re-implemented here this.generateCommitMessage = async (messages) => { @@ -88734,11 +88736,9 @@ var GenerateCommitMessageErrorEnum = ((GenerateCommitMessageErrorEnum2) => { return GenerateCommitMessageErrorEnum2; })(GenerateCommitMessageErrorEnum || {}); async function handleModelNotFoundError(error, provider, currentModel) { - console.log( - source_default.red(` + console.log(source_default.red(` \u2716 Model '${currentModel}' not found -`) - ); +`)); const suggestedModels = getSuggestedModels(provider, currentModel); const recommended = RECOMMENDED_MODELS[provider]; if (suggestedModels.length === 0) { diff --git a/src/cli.ts b/src/cli.ts index f9b6e17e..db308f2e 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -24,7 +24,13 @@ cli( { version: packageJSON.version, name: 'opencommit', - commands: [configCommand, hookCommand, commitlintConfigCommand, setupCommand, modelsCommand], + commands: [ + configCommand, + hookCommand, + commitlintConfigCommand, + setupCommand, + modelsCommand + ], flags: { fgm: { type: Boolean, @@ -48,28 +54,29 @@ cli( help: { description: packageJSON.description } }, async ({ flags }) => { + if (await isHookCalled()) { + await prepareCommitMessageHook(); + return; + } + await runMigrations(); await checkIsLatestVersion(); - if (await isHookCalled()) { - prepareCommitMessageHook(); - } else { - // Check for first run and trigger setup wizard - if (isFirstRun()) { - const setupComplete = await runSetup(); - if (!setupComplete) { - process.exit(1); - } - } - - // Check for missing API key and prompt if needed - const hasApiKey = await promptForMissingApiKey(); - if (!hasApiKey) { + // Check for first run and trigger setup wizard + if (isFirstRun()) { + const setupComplete = await runSetup(); + if (!setupComplete) { process.exit(1); } + } - commit(extraArgs, flags.context, false, flags.fgm, flags.yes); + // Check for missing API key and prompt if needed + const hasApiKey = await promptForMissingApiKey(); + if (!hasApiKey) { + process.exit(1); } + + commit(extraArgs, flags.context, false, flags.fgm, flags.yes); }, extraArgs ); diff --git a/src/commands/commit.ts b/src/commands/commit.ts index 70b5ef8b..6cd70485 100644 --- a/src/commands/commit.ts +++ b/src/commands/commit.ts @@ -11,10 +11,7 @@ import { import chalk from 'chalk'; import { execa } from 'execa'; import { generateCommitMessageByDiff } from '../generateCommitMessageFromGitDiff'; -import { - formatUserFriendlyError, - printFormattedError -} from '../utils/errors'; +import { formatUserFriendlyError, printFormattedError } from '../utils/errors'; import { assertGitRepo, getChangedFiles, diff --git a/src/commands/config.ts b/src/commands/config.ts index ba4cb124..7912e77f 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -849,7 +849,8 @@ export enum OCO_AI_PROVIDER_ENUM { export const PROVIDER_API_KEY_URLS: Record = { [OCO_AI_PROVIDER_ENUM.OPENAI]: 'https://platform.openai.com/api-keys', - [OCO_AI_PROVIDER_ENUM.ANTHROPIC]: 'https://console.anthropic.com/settings/keys', + [OCO_AI_PROVIDER_ENUM.ANTHROPIC]: + 'https://console.anthropic.com/settings/keys', [OCO_AI_PROVIDER_ENUM.GEMINI]: 'https://aistudio.google.com/app/apikey', [OCO_AI_PROVIDER_ENUM.GROQ]: 'https://console.groq.com/keys', [OCO_AI_PROVIDER_ENUM.MISTRAL]: 'https://console.mistral.ai/api-keys/', @@ -872,7 +873,7 @@ export const RECOMMENDED_MODELS: Record = { [OCO_AI_PROVIDER_ENUM.DEEPSEEK]: 'deepseek-chat', [OCO_AI_PROVIDER_ENUM.OPENROUTER]: 'openai/gpt-4o-mini', [OCO_AI_PROVIDER_ENUM.AIMLAPI]: 'gpt-4o-mini' -} +}; export type ConfigType = { [CONFIG_KEYS.OCO_API_KEY]?: string; diff --git a/src/commands/models.ts b/src/commands/models.ts index c4ecf06f..bd594a29 100644 --- a/src/commands/models.ts +++ b/src/commands/models.ts @@ -2,11 +2,7 @@ import { intro, outro, spinner } from '@clack/prompts'; import chalk from 'chalk'; import { command } from 'cleye'; import { COMMANDS } from './ENUMS'; -import { - MODEL_LIST, - OCO_AI_PROVIDER_ENUM, - getConfig -} from './config'; +import { MODEL_LIST, OCO_AI_PROVIDER_ENUM, getConfig } from './config'; import { fetchModelsForProvider, clearModelCache, @@ -31,7 +27,10 @@ function formatCacheAge(timestamp: number | null): string { return 'just now'; } -async function listModels(provider: string, useCache: boolean = true): Promise { +async function listModels( + provider: string, + useCache: boolean = true +): Promise { const config = getConfig(); const apiKey = config.OCO_API_KEY; const currentModel = config.OCO_MODEL; @@ -52,7 +51,9 @@ async function listModels(provider: string, useCache: boolean = true): Promise { clearModelCache(); try { - const models = await fetchModelsForProvider(provider, apiKey, undefined, true); + const models = await fetchModelsForProvider( + provider, + apiKey, + undefined, + true + ); loadingSpinner.stop(`${chalk.green('+')} Fetched ${models.length} models`); // List the models await listModels(provider, true); } catch (error) { loadingSpinner.stop(chalk.red('Failed to fetch models')); - console.error(chalk.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); + console.error( + chalk.red( + `Error: ${error instanceof Error ? error.message : 'Unknown error'}` + ) + ); } } @@ -112,7 +122,8 @@ export const modelsCommand = command( }, async ({ flags }) => { const config = getConfig(); - const provider = flags.provider || config.OCO_AI_PROVIDER || OCO_AI_PROVIDER_ENUM.OPENAI; + const provider = + flags.provider || config.OCO_AI_PROVIDER || OCO_AI_PROVIDER_ENUM.OPENAI; intro(chalk.bgCyan(' OpenCommit Models ')); @@ -120,7 +131,9 @@ export const modelsCommand = command( const cacheInfo = getCacheInfo(); if (cacheInfo.timestamp) { console.log( - chalk.dim(` Cache last updated: ${formatCacheAge(cacheInfo.timestamp)}`) + chalk.dim( + ` Cache last updated: ${formatCacheAge(cacheInfo.timestamp)}` + ) ); if (cacheInfo.providers.length > 0) { console.log( @@ -137,8 +150,6 @@ export const modelsCommand = command( await listModels(provider); } - outro( - `Run ${chalk.cyan('oco models --refresh')} to update the model list` - ); + outro(`Run ${chalk.cyan('oco models --refresh')} to update the model list`); } ); diff --git a/src/commands/setup.ts b/src/commands/setup.ts index 517750f9..7f044e51 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -52,6 +52,12 @@ const OTHER_PROVIDERS = [ ]; const NO_API_KEY_PROVIDERS = [ + OCO_AI_PROVIDER_ENUM.OLLAMA, + OCO_AI_PROVIDER_ENUM.MLX, + OCO_AI_PROVIDER_ENUM.TEST +]; + +const MODEL_REQUIRED_PROVIDERS = [ OCO_AI_PROVIDER_ENUM.OLLAMA, OCO_AI_PROVIDER_ENUM.MLX ]; @@ -90,7 +96,8 @@ async function selectProvider(): Promise { } async function getApiKey(provider: string): Promise { - const url = PROVIDER_API_KEY_URLS[provider as keyof typeof PROVIDER_API_KEY_URLS]; + const url = + PROVIDER_API_KEY_URLS[provider as keyof typeof PROVIDER_API_KEY_URLS]; let message = `Enter your ${provider} API key:`; if (url) { @@ -127,7 +134,8 @@ async function selectModel( provider: string, apiKey?: string ): Promise { - const providerDisplayName = PROVIDER_DISPLAY_NAMES[provider]?.split(' (')[0] || provider; + const providerDisplayName = + PROVIDER_DISPLAY_NAMES[provider]?.split(' (')[0] || provider; const loadingSpinner = spinner(); loadingSpinner.start(`Fetching models from ${providerDisplayName}...`); @@ -178,7 +186,8 @@ async function selectModel( } // Get recommended model for this provider - const recommended = RECOMMENDED_MODELS[provider as keyof typeof RECOMMENDED_MODELS]; + const recommended = + RECOMMENDED_MODELS[provider as keyof typeof RECOMMENDED_MODELS]; // Build options with recommended first const options: Array<{ value: string; label: string }> = []; @@ -191,9 +200,7 @@ async function selectModel( } // Add other models (first 10, excluding recommended) - const otherModels = models - .filter((m) => m !== recommended) - .slice(0, 10); + const otherModels = models.filter((m) => m !== recommended).slice(0, 10); otherModels.forEach((model) => { options.push({ value: model, label: model }); @@ -409,27 +416,31 @@ export async function runSetup(): Promise { setGlobalConfig(newConfig as any); outro( - `${chalk.green('āœ”')} Configuration saved to ~/.opencommit\n\n Run ${chalk.cyan('oco')} to generate commit messages!` + `${chalk.green( + 'āœ”' + )} Configuration saved to ~/.opencommit\n\n Run ${chalk.cyan( + 'oco' + )} to generate commit messages!` ); return true; } export function isFirstRun(): boolean { - if (!getIsGlobalConfigFileExist()) { - return true; - } - const config = getConfig(); // Check if API key is missing for providers that need it const provider = config.OCO_AI_PROVIDER || OCO_AI_PROVIDER_ENUM.OPENAI; - if (NO_API_KEY_PROVIDERS.includes(provider as OCO_AI_PROVIDER_ENUM)) { + if (MODEL_REQUIRED_PROVIDERS.includes(provider as OCO_AI_PROVIDER_ENUM)) { // For Ollama/MLX, check if model is set return !config.OCO_MODEL; } + if (provider === OCO_AI_PROVIDER_ENUM.TEST) { + return false; + } + // For other providers, check if API key is set return !config.OCO_API_KEY; } @@ -447,9 +458,7 @@ export async function promptForMissingApiKey(): Promise { } console.log( - chalk.yellow( - `\nAPI key missing for ${provider}. Let's set it up.\n` - ) + chalk.yellow(`\nAPI key missing for ${provider}. Let's set it up.\n`) ); const apiKey = await getApiKey(provider); diff --git a/src/generateCommitMessageFromGitDiff.ts b/src/generateCommitMessageFromGitDiff.ts index 19f23409..fa2c403c 100644 --- a/src/generateCommitMessageFromGitDiff.ts +++ b/src/generateCommitMessageFromGitDiff.ts @@ -55,9 +55,7 @@ async function handleModelNotFoundError( provider: string, currentModel: string ): Promise { - console.log( - chalk.red(`\nāœ– Model '${currentModel}' not found\n`) - ); + console.log(chalk.red(`\nāœ– Model '${currentModel}' not found\n`)); const suggestedModels = getSuggestedModels(provider, currentModel); const recommended = diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 190a0165..1fd9887d 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -3,15 +3,18 @@ import { MODEL_LIST, OCO_AI_PROVIDER_ENUM } from '../commands/config'; // Provider billing/help URLs for common errors export const PROVIDER_BILLING_URLS: Record = { - [OCO_AI_PROVIDER_ENUM.ANTHROPIC]: 'https://console.anthropic.com/settings/billing', - [OCO_AI_PROVIDER_ENUM.OPENAI]: 'https://platform.openai.com/settings/organization/billing', + [OCO_AI_PROVIDER_ENUM.ANTHROPIC]: + 'https://console.anthropic.com/settings/billing', + [OCO_AI_PROVIDER_ENUM.OPENAI]: + 'https://platform.openai.com/settings/organization/billing', [OCO_AI_PROVIDER_ENUM.GEMINI]: 'https://aistudio.google.com/app/plan', [OCO_AI_PROVIDER_ENUM.GROQ]: 'https://console.groq.com/settings/billing', [OCO_AI_PROVIDER_ENUM.MISTRAL]: 'https://console.mistral.ai/billing/', [OCO_AI_PROVIDER_ENUM.DEEPSEEK]: 'https://platform.deepseek.com/usage', [OCO_AI_PROVIDER_ENUM.OPENROUTER]: 'https://openrouter.ai/credits', [OCO_AI_PROVIDER_ENUM.AIMLAPI]: 'https://aimlapi.com/app/billing', - [OCO_AI_PROVIDER_ENUM.AZURE]: 'https://portal.azure.com/#view/Microsoft_Azure_CostManagement', + [OCO_AI_PROVIDER_ENUM.AZURE]: + 'https://portal.azure.com/#view/Microsoft_Azure_CostManagement', [OCO_AI_PROVIDER_ENUM.OLLAMA]: null, [OCO_AI_PROVIDER_ENUM.MLX]: null, [OCO_AI_PROVIDER_ENUM.FLOWISE]: null, @@ -23,7 +26,9 @@ export class InsufficientCreditsError extends Error { public readonly provider: string; constructor(provider: string, message?: string) { - super(message || `Insufficient credits or quota for provider '${provider}'`); + super( + message || `Insufficient credits or quota for provider '${provider}'` + ); this.name = 'InsufficientCreditsError'; this.provider = provider; } @@ -345,7 +350,10 @@ export interface FormattedError { } // Format an error into a user-friendly structure -export function formatUserFriendlyError(error: unknown, provider: string): FormattedError { +export function formatUserFriendlyError( + error: unknown, + provider: string +): FormattedError { const billingUrl = PROVIDER_BILLING_URLS[provider] || null; // Handle our custom error types first @@ -460,7 +468,9 @@ export function printFormattedError(formatted: FormattedError): string { output += ` ${formatted.message}\n`; if (formatted.helpUrl) { - output += `\n ${chalk.cyan('Help:')} ${chalk.underline(formatted.helpUrl)}\n`; + output += `\n ${chalk.cyan('Help:')} ${chalk.underline( + formatted.helpUrl + )}\n`; } if (formatted.suggestion) { diff --git a/src/utils/modelCache.ts b/src/utils/modelCache.ts index f1bd8d55..76ffc214 100644 --- a/src/utils/modelCache.ts +++ b/src/utils/modelCache.ts @@ -125,9 +125,7 @@ export async function fetchMistralModels(apiKey: string): Promise { } const data = await response.json(); - const models = data.data - ?.map((m: { id: string }) => m.id) - .sort(); + const models = data.data?.map((m: { id: string }) => m.id).sort(); return models && models.length > 0 ? models : MODEL_LIST.mistral; } catch { @@ -148,9 +146,7 @@ export async function fetchGroqModels(apiKey: string): Promise { } const data = await response.json(); - const models = data.data - ?.map((m: { id: string }) => m.id) - .sort(); + const models = data.data?.map((m: { id: string }) => m.id).sort(); return models && models.length > 0 ? models : MODEL_LIST.groq; } catch { @@ -173,8 +169,9 @@ export async function fetchOpenRouterModels(apiKey: string): Promise { const data = await response.json(); // Filter to text-capable models only (exclude image/audio models) const models = data.data - ?.filter((m: { id: string; context_length?: number }) => - m.context_length && m.context_length > 0 + ?.filter( + (m: { id: string; context_length?: number }) => + m.context_length && m.context_length > 0 ) .map((m: { id: string }) => m.id) .sort(); @@ -198,9 +195,7 @@ export async function fetchDeepSeekModels(apiKey: string): Promise { } const data = await response.json(); - const models = data.data - ?.map((m: { id: string }) => m.id) - .sort(); + const models = data.data?.map((m: { id: string }) => m.id).sort(); return models && models.length > 0 ? models : MODEL_LIST.deepseek; } catch { @@ -312,7 +307,10 @@ export function clearModelCache(): void { } } -export function getCacheInfo(): { timestamp: number | null; providers: string[] } { +export function getCacheInfo(): { + timestamp: number | null; + providers: string[]; +} { const cache = readCache(); if (!cache) { return { timestamp: null, providers: [] }; diff --git a/test/e2e/gitPush.test.ts b/test/e2e/gitPush.test.ts index 7062ef0a..714254ed 100644 --- a/test/e2e/gitPush.test.ts +++ b/test/e2e/gitPush.test.ts @@ -9,6 +9,11 @@ import { rm } from 'fs'; const fsExec = promisify(exec); const fsRemove = promisify(rm); +const waitForCommitConfirmation = async (findByText: any) => { + expect(await findByText('Generating the commit message')).toBeInTheConsole(); + expect(await findByText('Confirm the commit message?')).toBeInTheConsole(); +}; + /** * git remote -v * @@ -97,7 +102,7 @@ describe('cli flow to push git branch', () => { [resolve('./out/cli.cjs')], { cwd: gitDir } ); - expect(await findByText('Confirm the commit message?')).toBeInTheConsole(); + await waitForCommitConfirmation(findByText); userEvent.keyboard('[Enter]'); expect( @@ -129,7 +134,7 @@ describe('cli flow to push git branch', () => { [resolve('./out/cli.cjs')], { cwd: gitDir } ); - expect(await findByText('Confirm the commit message?')).toBeInTheConsole(); + await waitForCommitConfirmation(findByText); userEvent.keyboard('[Enter]'); expect( @@ -162,7 +167,7 @@ describe('cli flow to push git branch', () => { [resolve('./out/cli.cjs')], { cwd: gitDir } ); - expect(await findByText('Confirm the commit message?')).toBeInTheConsole(); + await waitForCommitConfirmation(findByText); userEvent.keyboard('[Enter]'); expect( @@ -190,7 +195,7 @@ describe('cli flow to push git branch', () => { [resolve('./out/cli.cjs')], { cwd: gitDir } ); - expect(await findByText('Confirm the commit message?')).toBeInTheConsole(); + await waitForCommitConfirmation(findByText); userEvent.keyboard('[Enter]'); expect(await findByText('Choose a remote to push to')).toBeInTheConsole(); diff --git a/test/e2e/prompt-module/commitlint.test.ts b/test/e2e/prompt-module/commitlint.test.ts index 643db37b..680203f7 100644 --- a/test/e2e/prompt-module/commitlint.test.ts +++ b/test/e2e/prompt-module/commitlint.test.ts @@ -3,6 +3,10 @@ import { render } from 'cli-testing-library'; import 'cli-testing-library/extend-expect'; import { prepareEnvironment, wait } from '../utils'; import path from 'path'; +import { execFile } from 'child_process'; +import { promisify } from 'util'; + +const execFileAsync = promisify(execFile); function getAbsolutePath(relativePath: string) { // Use process.cwd() which should be the project root during test execution @@ -27,9 +31,10 @@ async function setupCommitlint(dir: string, ver: 9 | 18 | 19) { configPath = getAbsolutePath('./data/commitlint_19/commitlint.config.js'); break; } - await render('cp', ['-r', packagePath, '.'], { cwd: dir }); - await render('cp', [packageJsonPath, '.'], { cwd: dir }); - await render('cp', [configPath, '.'], { cwd: dir }); + + await execFileAsync('cp', ['-R', packagePath, path.join(dir, 'node_modules')]); + await execFileAsync('cp', [packageJsonPath, path.join(dir, 'package.json')]); + await execFileAsync('cp', [configPath, path.join(dir, 'commitlint.config.js')]); await wait(3000); // Avoid flakiness by waiting }