@@ -11,7 +11,10 @@
|
||||
"test": "jest",
|
||||
"lint": "eslint src/",
|
||||
"prepublishOnly": "npm test && npm run lint",
|
||||
"postinstall": "echo 'Thanks for installing alepm! Run: alepm --help to get started.'"
|
||||
"postinstall": "echo 'Thanks for installing alepm! Run: alepm --help to get started.'",
|
||||
"hello": "echo 'Hello from alepm!'",
|
||||
"date": "date",
|
||||
"version": "echo 'alepm version:' && node -e \"console.log(require('./package.json').version)\""
|
||||
},
|
||||
"keywords": [
|
||||
"package-manager",
|
||||
|
||||
15
src/cli.js
15
src/cli.js
@@ -105,6 +105,21 @@ program
|
||||
}
|
||||
});
|
||||
|
||||
// Run command
|
||||
program
|
||||
.command('run <script>')
|
||||
.description('Run a script from package.json')
|
||||
.option('--silent', 'Suppress output from npm scripts')
|
||||
.option('--if-present', 'Don\'t error if script is missing')
|
||||
.action(async (script, options) => {
|
||||
try {
|
||||
await pm.runScript(script, options);
|
||||
} catch (error) {
|
||||
console.error(chalk.red(`Error: ${error.message}`));
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Cache commands
|
||||
program
|
||||
.command('cache')
|
||||
|
||||
@@ -15,7 +15,7 @@ const ConfigManager = require('../utils/config-manager');
|
||||
const Logger = require('../utils/logger');
|
||||
|
||||
class PackageManager {
|
||||
constructor() {
|
||||
constructor(options = {}) {
|
||||
this.cache = new CacheManager();
|
||||
this.security = new SecurityManager();
|
||||
this.storage = new BinaryStorage();
|
||||
@@ -29,7 +29,7 @@ class PackageManager {
|
||||
this.resolver.setRegistry(this.registry);
|
||||
this.resolver.setLockManager(this.lock);
|
||||
|
||||
this.projectRoot = this.findProjectRoot();
|
||||
this.projectRoot = options.projectRoot || this.findProjectRoot();
|
||||
this.globalRoot = path.join(require('os').homedir(), '.alepm');
|
||||
|
||||
this.initialized = false;
|
||||
@@ -596,6 +596,115 @@ class PackageManager {
|
||||
}
|
||||
}
|
||||
|
||||
async runScript(scriptName, options = {}) {
|
||||
await this.ensureInitialized();
|
||||
|
||||
const packageJsonPath = path.join(this.projectRoot, 'package.json');
|
||||
|
||||
if (!await fs.pathExists(packageJsonPath)) {
|
||||
throw new Error('No package.json found in current directory');
|
||||
}
|
||||
|
||||
const packageJson = await fs.readJson(packageJsonPath);
|
||||
|
||||
if (!packageJson.scripts) {
|
||||
if (options.ifPresent) {
|
||||
console.log(chalk.yellow('No scripts section found in package.json'));
|
||||
return;
|
||||
}
|
||||
throw new Error('No scripts section found in package.json');
|
||||
}
|
||||
|
||||
const script = packageJson.scripts[scriptName];
|
||||
|
||||
if (!script) {
|
||||
if (options.ifPresent) {
|
||||
console.log(chalk.yellow(`Script "${scriptName}" not found`));
|
||||
return;
|
||||
}
|
||||
|
||||
// Show available scripts
|
||||
const availableScripts = Object.keys(packageJson.scripts);
|
||||
console.log(chalk.red(`Script "${scriptName}" not found.`));
|
||||
if (availableScripts.length > 0) {
|
||||
console.log(chalk.blue('Available scripts:'));
|
||||
availableScripts.forEach(name => {
|
||||
console.log(chalk.gray(` ${name}: ${packageJson.scripts[name]}`));
|
||||
});
|
||||
}
|
||||
throw new Error(`Script "${scriptName}" not found`);
|
||||
}
|
||||
|
||||
console.log(chalk.blue(`Running script: ${scriptName}`));
|
||||
console.log(chalk.gray(`> ${script}`));
|
||||
console.log('');
|
||||
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// Determine shell based on OS
|
||||
const isWindows = process.platform === 'win32';
|
||||
const shell = isWindows ? 'cmd' : 'sh';
|
||||
const shellFlag = isWindows ? '/c' : '-c';
|
||||
|
||||
const childProcess = spawn(shell, [shellFlag, script], {
|
||||
cwd: this.projectRoot,
|
||||
stdio: options.silent ? 'pipe' : 'inherit',
|
||||
shell: true,
|
||||
env: {
|
||||
...process.env,
|
||||
// Add node_modules/.bin to PATH
|
||||
PATH: `${path.join(this.projectRoot, 'node_modules', '.bin')}${path.delimiter}${process.env.PATH}`
|
||||
}
|
||||
});
|
||||
|
||||
// Handle silent mode
|
||||
if (options.silent) {
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
if (childProcess.stdout) {
|
||||
childProcess.stdout.on('data', (data) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
}
|
||||
|
||||
if (childProcess.stderr) {
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
}
|
||||
|
||||
childProcess.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
if (stdout.trim()) {
|
||||
console.log(stdout.trim());
|
||||
}
|
||||
resolve();
|
||||
} else {
|
||||
if (stderr.trim()) {
|
||||
console.error(stderr.trim());
|
||||
}
|
||||
reject(new Error(`Script "${scriptName}" exited with code ${code}`));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
childProcess.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
console.log(chalk.green(`✓ Script "${scriptName}" completed successfully`));
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Script "${scriptName}" exited with code ${code}`));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
childProcess.on('error', (error) => {
|
||||
reject(new Error(`Failed to run script "${scriptName}": ${error.message}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async verifyLock() {
|
||||
const spinner = ora('Verifying lock file...').start();
|
||||
|
||||
|
||||
135
tests/run-command.test.js
Archivo normal
135
tests/run-command.test.js
Archivo normal
@@ -0,0 +1,135 @@
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const PackageManager = require('../src/core/package-manager');
|
||||
|
||||
describe('Run Command', () => {
|
||||
let tempDir;
|
||||
let packageManager;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempDir = path.join(__dirname, 'temp-run-test');
|
||||
await fs.ensureDir(tempDir);
|
||||
packageManager = new PackageManager({ projectRoot: tempDir });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (await fs.pathExists(tempDir)) {
|
||||
await fs.remove(tempDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('should run a simple script successfully', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
hello: 'echo "Hello World"'
|
||||
}
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
// This should not throw
|
||||
await packageManager.runScript('hello');
|
||||
});
|
||||
|
||||
test('should fail when script does not exist', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
hello: 'echo "Hello World"'
|
||||
}
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
await expect(packageManager.runScript('nonexistent')).rejects.toThrow(
|
||||
'Script "nonexistent" not found'
|
||||
);
|
||||
});
|
||||
|
||||
test('should not fail when script does not exist with ifPresent option', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
hello: 'echo "Hello World"'
|
||||
}
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
// This should not throw
|
||||
await packageManager.runScript('nonexistent', { ifPresent: true });
|
||||
});
|
||||
|
||||
test('should fail when package.json does not exist', async () => {
|
||||
// Override ensureInitialized to prevent auto-creation
|
||||
const originalEnsureInitialized = packageManager.ensureInitialized;
|
||||
packageManager.ensureInitialized = async () => {};
|
||||
|
||||
await expect(packageManager.runScript('hello')).rejects.toThrow(
|
||||
'No package.json found in current directory'
|
||||
);
|
||||
|
||||
// Restore original method
|
||||
packageManager.ensureInitialized = originalEnsureInitialized;
|
||||
});
|
||||
|
||||
test('should fail when package.json has no scripts section', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
await expect(packageManager.runScript('hello')).rejects.toThrow(
|
||||
'No scripts section found in package.json'
|
||||
);
|
||||
});
|
||||
|
||||
test('should not fail when package.json has no scripts section with ifPresent option', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0'
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
// This should not throw
|
||||
await packageManager.runScript('hello', { ifPresent: true });
|
||||
});
|
||||
|
||||
test('should run script with silent option', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
hello: 'echo "Hello World"'
|
||||
}
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
// This should not throw
|
||||
await packageManager.runScript('hello', { silent: true });
|
||||
});
|
||||
|
||||
test('should handle script that exits with error code', async () => {
|
||||
const packageJson = {
|
||||
name: 'test-package',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
fail: 'nonexistentcommand123456' // This command doesn't exist
|
||||
}
|
||||
};
|
||||
|
||||
await fs.writeJson(path.join(tempDir, 'package.json'), packageJson);
|
||||
|
||||
await expect(packageManager.runScript('fail')).rejects.toThrow(
|
||||
'Script "fail" exited with code 127'
|
||||
);
|
||||
});
|
||||
});
|
||||
Referencia en una nueva incidencia
Block a user