Files
michaelschiemer/src/Framework/Process/Services/NpmService.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

363 lines
9.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Process\Services;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Process\Process;
use App\Framework\Process\ValueObjects\Command;
use App\Framework\Process\ValueObjects\Npm\NpmAuditResult;
use App\Framework\Process\ValueObjects\Npm\NpmPackage;
/**
* NPM Service.
*
* Verwaltet NPM-Operationen wie Installations, Updates, Security Audits und Package-Informationen.
*/
final readonly class NpmService
{
public function __construct(
private Process $process,
private ?FilePath $projectRoot = null
) {
}
/**
* Gibt die NPM-Version zurück.
*/
public function getVersion(): string
{
$result = $this->process->run(
Command::fromArray(['npm', '--version'])
);
if (! $result->isSuccess()) {
return 'unknown';
}
return trim($result->stdout);
}
/**
* Installiert Dependencies.
*/
public function install(bool $production = false): bool
{
$args = ['npm', 'install'];
if ($production) {
$args[] = '--production';
}
$result = $this->process->run(
command: Command::fromArray($args),
workingDirectory: $this->projectRoot,
timeout: Duration::fromMinutes(5)
);
return $result->isSuccess();
}
/**
* Aktualisiert Dependencies.
*/
public function update(bool $production = false): bool
{
$args = ['npm', 'update'];
if ($production) {
$args[] = '--production';
}
$result = $this->process->run(
command: Command::fromArray($args),
workingDirectory: $this->projectRoot,
timeout: Duration::fromMinutes(10)
);
return $result->isSuccess();
}
/**
* Führt Security Audit durch.
*/
public function audit(): NpmAuditResult
{
$result = $this->process->run(
command: Command::fromArray(['npm', 'audit', '--json']),
workingDirectory: $this->projectRoot,
timeout: Duration::fromSeconds(60)
);
if (! $result->isSuccess()) {
// Auch bei Vulnerabilities ist Exit-Code != 0
// Versuche trotzdem JSON zu parsen
}
$data = json_decode($result->stdout, true);
if (! is_array($data)) {
return NpmAuditResult::safe();
}
return NpmAuditResult::fromAuditJson($data);
}
/**
* Versucht automatisches Fixing von Vulnerabilities.
*/
public function auditFix(bool $force = false): bool
{
$args = ['npm', 'audit', 'fix'];
if ($force) {
$args[] = '--force';
}
$result = $this->process->run(
command: Command::fromArray($args),
workingDirectory: $this->projectRoot,
timeout: Duration::fromMinutes(5)
);
return $result->isSuccess();
}
/**
* Listet veraltete Packages auf.
*
* @return NpmPackage[]
*/
public function getOutdatedPackages(): array
{
$result = $this->process->run(
command: Command::fromArray(['npm', 'outdated', '--json']),
workingDirectory: $this->projectRoot,
timeout: Duration::fromSeconds(60)
);
// npm outdated gibt Exit-Code != 0 wenn es outdated packages gibt
$data = json_decode($result->stdout, true);
if (! is_array($data)) {
return [];
}
$packages = [];
foreach ($data as $name => $info) {
$packages[] = NpmPackage::fromNpmOutput(
name: $name,
currentVersion: $info['current'] ?? 'unknown',
wantedVersion: $info['wanted'] ?? null,
latestVersion: $info['latest'] ?? null,
type: $info['type'] ?? null
);
}
return $packages;
}
/**
* Listet installierte Packages auf.
*
* @return NpmPackage[]
*/
public function getInstalledPackages(): array
{
$result = $this->process->run(
command: Command::fromArray(['npm', 'list', '--json', '--depth=0']),
workingDirectory: $this->projectRoot,
timeout: Duration::fromSeconds(30)
);
if (! $result->isSuccess()) {
return [];
}
$data = json_decode($result->stdout, true);
if (! is_array($data)) {
return [];
}
$packages = [];
// Dependencies
foreach ($data['dependencies'] ?? [] as $name => $info) {
$packages[] = new NpmPackage(
name: $name,
currentVersion: $info['version'] ?? 'unknown',
type: 'dependencies'
);
}
// DevDependencies (wenn --depth=0 nicht nur dependencies zurückgibt)
foreach ($data['devDependencies'] ?? [] as $name => $info) {
$packages[] = new NpmPackage(
name: $name,
currentVersion: $info['version'] ?? 'unknown',
type: 'devDependencies'
);
}
return $packages;
}
/**
* Führt NPM Script aus.
*/
public function runScript(string $script): bool
{
$result = $this->process->run(
command: Command::fromArray(['npm', 'run', $script]),
workingDirectory: $this->projectRoot,
timeout: Duration::fromMinutes(10)
);
return $result->isSuccess();
}
/**
* Cleaned node_modules und package-lock.json.
*/
public function clean(): bool
{
if ($this->projectRoot === null) {
return false;
}
$nodeModules = $this->projectRoot->toString() . '/node_modules';
$packageLock = $this->projectRoot->toString() . '/package-lock.json';
// Remove node_modules
if (is_dir($nodeModules)) {
$result = $this->process->run(
command: Command::fromArray(['rm', '-rf', $nodeModules]),
timeout: Duration::fromMinutes(2)
);
if (! $result->isSuccess()) {
return false;
}
}
// Remove package-lock.json
if (file_exists($packageLock)) {
$result = $this->process->run(
command: Command::fromArray(['rm', $packageLock]),
timeout: Duration::fromSeconds(5)
);
if (! $result->isSuccess()) {
return false;
}
}
return true;
}
/**
* Prüft package.json Validität.
*/
public function validate(): bool
{
if ($this->projectRoot === null) {
return false;
}
$packageJson = $this->projectRoot->toString() . '/package.json';
if (! file_exists($packageJson)) {
return false;
}
$content = file_get_contents($packageJson);
$data = json_decode($content, true);
// Grundlegende Validierung
return is_array($data)
&& isset($data['name'])
&& isset($data['version']);
}
/**
* Initialisiert neues NPM-Projekt.
*/
public function init(bool $yes = false): bool
{
$args = ['npm', 'init'];
if ($yes) {
$args[] = '--yes';
}
$result = $this->process->run(
command: Command::fromArray($args),
workingDirectory: $this->projectRoot,
timeout: Duration::fromSeconds(30)
);
return $result->isSuccess();
}
/**
* Installiert spezifisches Package.
*/
public function installPackage(string $package, bool $dev = false, bool $exact = false): bool
{
$args = ['npm', 'install', $package];
if ($dev) {
$args[] = '--save-dev';
}
if ($exact) {
$args[] = '--save-exact';
}
$result = $this->process->run(
command: Command::fromArray($args),
workingDirectory: $this->projectRoot,
timeout: Duration::fromMinutes(3)
);
return $result->isSuccess();
}
/**
* Deinstalliert spezifisches Package.
*/
public function uninstallPackage(string $package): bool
{
$result = $this->process->run(
command: Command::fromArray(['npm', 'uninstall', $package]),
workingDirectory: $this->projectRoot,
timeout: Duration::fromMinutes(2)
);
return $result->isSuccess();
}
/**
* Zeigt Package-Informationen.
*/
public function showPackageInfo(string $package): ?array
{
$result = $this->process->run(
command: Command::fromArray(['npm', 'show', $package, '--json']),
timeout: Duration::fromSeconds(30)
);
if (! $result->isSuccess()) {
return null;
}
$data = json_decode($result->stdout, true);
return is_array($data) ? $data : null;
}
}