From 93033160a17f5587eb7d2496cca5d5f8508a6a96 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Thu, 9 Apr 2026 17:21:31 -0300 Subject: [PATCH] fix: ask before installing local packages. --- src/environment-full.ts | 16 +++++++++++++++- test/command.js | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/environment-full.ts b/src/environment-full.ts index 6f6726a6..61168ffa 100644 --- a/src/environment-full.ts +++ b/src/environment-full.ts @@ -226,9 +226,23 @@ class FullEnvironment extends EnvironmentBase { * @param {Object} packages - packages to install key(packageName): value(versionRange). * @return {Boolean} - true if the install succeeded. */ - async installLocalGenerators(packages: Record) { + async installLocalGenerators(packages: Record, forceInstall = false) { const entries = Object.entries(packages); const specs = entries.map(([packageName, version]) => `${packageName}${version ? `@${version}` : ''}`); + if (forceInstall) { + this.adapter.log.info(`Force install is enabled. Proceeding with installation.`); + } else { + const { aproveInstall } = await this.adapter.prompt({ + message: `The following packages need to be installed in the local repository: ${specs.join(', ')}. Do you want to proceed?`, + type: 'confirm', + name: 'aproveInstall', + default: false, + }); + if (!aproveInstall) { + throw new Error(`Installation of ${specs.join(', ')} is declined by the user. Install manually and try again.`); + } + } + this.adapter.log.info(`The following packages will be installed in the local repository: ${specs.join(', ')}.`); const installResult = await this.repository.install(specs); const failToInstall = installResult.find(result => !result.path); if (failToInstall) { diff --git a/test/command.js b/test/command.js index 081bda68..8a5f78c2 100644 --- a/test/command.js +++ b/test/command.js @@ -3,7 +3,8 @@ import path, { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { createRequire } from 'node:module'; import { stub } from 'sinon'; -import { beforeEach, describe, it } from 'esmocha'; +import { beforeEach, describe, esmocha, expect, it } from 'esmocha'; +import { TestAdapter } from 'yeoman-test'; import { prepareCommand } from '../src/commands.ts'; import Environment from '../src/index.ts'; @@ -12,11 +13,45 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); describe('environment (command)', () => { + describe('#execute()', () => { + let environment; + let adapter; + + beforeEach(async () => { + adapter = new TestAdapter(); + environment = new Environment({ skipInstall: true, dryRun: true, adapter }); + }); + + describe('with non existing generator', () => { + it('declining installation', async () => { + adapter.addAnswers({ + aproveInstall: false, + }); + environment.repository.install = esmocha.fn().mockReturnValue(Promise.resolve([])); + await expect(environment.execute('commands:options')).rejects.toThrow( + /Installation of generator-commands is declined by the user. Install manually and try again/, + ); + expect(environment.repository.install).not.toHaveBeenCalled(); + }); + + it('approving installation', async () => { + adapter.addAnswers({ + aproveInstall: true, + }); + environment.repository.install = esmocha.fn().mockReturnValue(Promise.resolve([])); + await expect(environment.execute('commands:options')).rejects.toThrow( + /You don't seem to have a generator with the name “generator-commands” installed./, + ); + expect(environment.repository.install).toHaveBeenCalledWith(['generator-commands']); + }); + }); + }); + describe('#execute() with options', () => { let environment; beforeEach(async () => { - environment = new Environment([], { skipInstall: true, dryRun: true }); + environment = new Environment({ skipInstall: true, dryRun: true }); environment.adapter.log = stub(); await environment.register(path.join(__dirname, 'fixtures/generator-commands/generators/options')); }); @@ -87,7 +122,7 @@ describe('environment (command)', () => { let environment; beforeEach(() => { - environment = new Environment([], { skipInstall: true, dryRun: true }); + environment = new Environment({ skipInstall: true, dryRun: true }); environment.adapter.log = stub(); environment.register(path.join(__dirname, 'fixtures/generator-commands/generators/arguments')); });