Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completed npm commands (npm:install, npm:update, npm:run) #1202

Merged
merged 30 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0780ac2
Added inital work on npm commands
jaxwilko Sep 12, 2024
2c6bea7
Added fix for root issued commands
jaxwilko Sep 12, 2024
05eaed4
Added npm:install command and moved scripts
jaxwilko Sep 12, 2024
cd62ba5
Added better error reporting and moved tests
jaxwilko Sep 15, 2024
9fbcc05
Added fixes for silent flag and added disable-tty as an option
jaxwilko Sep 20, 2024
8a76ea8
Added tests and fixtures
jaxwilko Sep 20, 2024
90a0d17
Renamed vitetest theme to assettest
jaxwilko Sep 23, 2024
e7e770d
Added fix to PackageJson to handle malformed json files
jaxwilko Sep 23, 2024
3d3b2bf
Added caching of package.json file and dynamic ignored loading to ena…
jaxwilko Sep 23, 2024
b5b3b97
Added simplification and support for testing to asset:install commands
jaxwilko Sep 23, 2024
d27911f
Added catch used by original command
jaxwilko Sep 23, 2024
4b53b50
Removed incorrect alias
jaxwilko Sep 23, 2024
f0dcdf7
Added fix for theme rename
jaxwilko Sep 23, 2024
8bca2d1
Added trait for preserving package.json between tests logic
jaxwilko Sep 23, 2024
9c5394c
Updated eslintignore for test theme change
jaxwilko Sep 23, 2024
914cbea
Added test fixtures
jaxwilko Sep 23, 2024
e323a97
Added tests for asset install commands
jaxwilko Sep 23, 2024
2a222bf
Removed json_validate as it's only available in php8.3
jaxwilko Sep 23, 2024
a8b119f
Updated eslintignore
jaxwilko Sep 23, 2024
5b49911
Added SystemException as base for package exceptions
jaxwilko Sep 24, 2024
dc28b28
Added corrupt test for PackageJson
jaxwilko Sep 24, 2024
54843a6
Added check for PackageManager to ensure the config file for a regist…
jaxwilko Sep 24, 2024
1969a0d
Renamed test package.json file
jaxwilko Sep 24, 2024
7c64366
Added fix for package json restoring and added test case for --packag…
jaxwilko Sep 24, 2024
76fec29
Update modules/system/console/asset/npm/NpmInstall.php
LukeTowers Sep 24, 2024
f8ff0dd
Update modules/system/console/asset/AssetInstall.php
LukeTowers Sep 24, 2024
c39bdb2
Added phpdocs
jaxwilko Oct 4, 2024
2b2ab51
Merge branch 'wip/npm-commands' of github.com:wintercms/winter into w…
jaxwilko Oct 4, 2024
4587abc
Merge branch 'develop' into wip/npm-commands
jaxwilko Oct 25, 2024
2f16357
Removed custom exceptions
jaxwilko Oct 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions modules/system/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,9 @@ protected function registerConsole()
$this->registerConsoleCommand('vite.list', Console\Asset\Vite\ViteList::class);
$this->registerConsoleCommand('vite.watch', Console\Asset\Vite\ViteWatch::class);

$this->registerConsoleCommand('npm.run', Console\Asset\NpmRun::class);
$this->registerConsoleCommand('npm.update', Console\Asset\NpmUpdate::class);
$this->registerConsoleCommand('npm.run', Console\Asset\Npm\NpmRun::class);
$this->registerConsoleCommand('npm.install', Console\Asset\Npm\NpmInstall::class);
$this->registerConsoleCommand('npm.update', Console\Asset\Npm\NpmUpdate::class);
}

/*
Expand Down
29 changes: 26 additions & 3 deletions modules/system/console/asset/AssetInstall.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use System\Classes\Asset\PackageJson;
use System\Classes\Asset\PackageManager;
use System\Classes\PluginManager;
use System\Console\Asset\Exceptions\PackageNotFoundException;
use Winter\Storm\Console\Command;
use Winter\Storm\Support\Facades\Config;
use Winter\Storm\Support\Facades\File;
Expand Down Expand Up @@ -194,14 +195,36 @@ protected function validateRequirePackagesPresent(PackageJson $packageJson): Pac

protected function processPackages(array $registeredPackages, PackageJson $packageJson): PackageJson
{
// Process each package
// Check if the user requested a specific package for install
$requestedPackage = strtolower($this->argument('assetPackage'));
$foundRequestedPackage = !$requestedPackage;

if (!$foundRequestedPackage) {
foreach ($registeredPackages as $name => $package) {
if ($requestedPackage === $name) {
$foundRequestedPackage = true;
}
}

// We did not find the package, exit
if (!$foundRequestedPackage) {
LukeTowers marked this conversation as resolved.
Show resolved Hide resolved
throw new PackageNotFoundException(sprintf(
'The requested package `%s` could not be found. Try %s:config or check if the package is ignored.',
$this->argument('assetPackage'),
$this->assetType
));
}
}

// Process each found package
foreach ($registeredPackages as $name => $package) {
// Normalize package path across OS types
$packagePath = Str::replace(DIRECTORY_SEPARATOR, '/', $package['path']);
// Add the package path to the instance's package.json->workspaces->packages property if not present
if (!$packageJson->hasWorkspace($packagePath) && !$packageJson->hasIgnoredPackage($packagePath)) {
if (
$this->confirm(
$requestedPackage === $name
|| $this->confirm(
sprintf(
"Detected %s (%s), should it be added to your package.json?",
$name,
Expand Down Expand Up @@ -242,7 +265,7 @@ protected function processPackages(array $registeredPackages, PackageJson $packa
*/
protected function installPackageDeps(): int
{
$command = $this->argument('npmArgs') ?? [];
$command = [];
array_unshift($command, 'npm', $this->npmCommand);

$process = new Process($command, base_path(), null, null, null);
Expand Down
67 changes: 67 additions & 0 deletions modules/system/console/asset/NpmCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace System\Console\Asset;
jaxwilko marked this conversation as resolved.
Show resolved Hide resolved

use Symfony\Component\Process\Process;
use System\Classes\Asset\PackageJson;
use System\Classes\Asset\PackageManager;
use System\Console\Asset\Exceptions\PackageNotRegisteredException;
use Winter\Storm\Console\Command;

abstract class NpmCommand extends Command
jaxwilko marked this conversation as resolved.
Show resolved Hide resolved
{
protected function getPackage(): ?array
{
$compilableAssets = PackageManager::instance();
$compilableAssets->fireCallbacks();

$name = $this->argument('package');

if (!$name) {
return null;
}

if (!$compilableAssets->hasPackage($name, true)) {
throw new PackageNotRegisteredException(sprintf('Package "%s" is not a registered package.', $name));
}

$package = $compilableAssets->getPackage($name, true)[0] ?? [];

// Assume that packages with matching names have matching package.json files
$packageJson = new PackageJson($package['package'] ?? null);

return [$package, $packageJson];
}

protected function npmRun(array $command, string $path): int
{
$process = new Process(
$command,
base_path($path),
['NODE_ENV' => $this->getNodeEnv()],
null,
null
);

try {
$process->setTty(true);
} catch (\Throwable $e) {
// This will fail on unsupported systems
}

return $process->run(function ($status, $stdout) {
if (!$this->option('silent')) {
$this->getOutput()->write($stdout);
}
});
}

protected function getNodeEnv(): string
{
if (!$this->hasOption('production')) {
return 'development';
}

return $this->option('production', false) ? 'production' : 'development';
}
}
46 changes: 0 additions & 46 deletions modules/system/console/asset/NpmUpdate.php

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace System\Console\Asset\Exceptions;

class PackageNotFoundException extends \InvalidArgumentException
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace System\Console\Asset\Exceptions;

class PackageNotRegisteredException extends \InvalidArgumentException
{

}
2 changes: 1 addition & 1 deletion modules/system/console/asset/mix/MixInstall.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MixInstall extends AssetInstall
* @var string The name and signature of this command.
*/
protected $signature = 'mix:install
{npmArgs?* : Arguments to pass through to the "npm" binary}
{assetPackage? : The asset package name to install}
{--npm= : Defines a custom path to the "npm" binary}
{--p|package=* : Defines one or more packages to install}';

Expand Down
54 changes: 54 additions & 0 deletions modules/system/console/asset/npm/NpmInstall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace System\console\asset\npm;
LukeTowers marked this conversation as resolved.
Show resolved Hide resolved

use System\Console\Asset\Exceptions\PackageNotRegisteredException;
use System\Console\Asset\NpmCommand;

class NpmInstall extends NpmCommand
{
/**
* @var string|null The default command name for lazy loading.
*/
protected static $defaultName = 'npm:install';

/**
* @inheritDoc
*/
protected $description = 'Install Node.js dependencies for a package';

/**
* @inheritDoc
*/
protected $signature = 'npm:install
{package? : The package name to add configuration for}
{npmArgs?* : Arguments to pass through to the "npm" binary}
{--npm= : Defines a custom path to the "npm" binary}
{--d|dev : Install packages in devDependencies}';

/**
* @inheritDoc
*/
public $replaces = [
'mix:update'
];

public function handle(): int
jaxwilko marked this conversation as resolved.
Show resolved Hide resolved
{
$command = ($this->argument('npmArgs')) ?? [];

try {
[$package, $packageJson] = $this->getPackage();
} catch (PackageNotRegisteredException $e) {
array_unshift($command, $this->argument('package'));
}

array_unshift($command, 'npm', 'install');

if ($this->option('dev')) {
$command[] = '--save-dev';
}

return $this->npmRun($command, $package['path'] ?? '');
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<?php

namespace System\Console\Asset;
namespace System\Console\Asset\Npm;

use Symfony\Component\Process\Process;
use System\Classes\Asset\PackageManager;
use System\Classes\Asset\PackageJson;
use Winter\Storm\Console\Command;
use System\Console\Asset\NpmCommand;

class NpmRun extends Command
class NpmRun extends NpmCommand
{
/**
* @var string|null The default command name for lazy loading.
Expand Down Expand Up @@ -41,32 +38,18 @@ class NpmRun extends Command
*/
public function handle(): int
{
$compilableAssets = PackageManager::instance();
$compilableAssets->fireCallbacks();
[$package, $packageJson] = $this->getPackage();

$name = $this->argument('package');
$script = $this->argument('script');

if (!$compilableAssets->hasPackage($name, true)) {
$this->error(
sprintf('Package "%s" is not a registered package.', $name)
);
return 1;
}

$package = $compilableAssets->getPackage($name, true)[0] ?? [];

// Assume that packages with matching names have matching package.json files
$packageJson = new PackageJson($package['package'] ?? null);

if (!$packageJson->hasScript($script)) {
$this->error(
sprintf('Script "%s" is not defined in package "%s".', $script, $name)
sprintf('Script "%s" is not defined in package "%s".', $script, $this->argument('package'))
);
return 1;
}

$this->info(sprintf('Running script "%s" in package "%s"', $script, $name));
$this->info(sprintf('Running script "%s" in package "%s"', $script, $this->argument('package')));

$command = ($this->argument('additionalArgs')) ?? [];
if (count($command)) {
Expand All @@ -75,25 +58,6 @@ public function handle(): int
array_unshift($command, 'npm', 'run', $script);
}


$process = new Process(
$command,
base_path($package['path']),
['NODE_ENV' => $this->option('production', false) ? 'production' : 'development'],
null,
null
);

try {
$process->setTty(true);
} catch (\Throwable $e) {
// This will fail on unsupported systems
}

return $process->run(function ($status, $stdout) {
if (!$this->option('silent')) {
$this->getOutput()->write($stdout);
}
});
return $this->npmRun($command, $package['path']);
}
}
53 changes: 53 additions & 0 deletions modules/system/console/asset/npm/NpmUpdate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace System\Console\Asset\Npm;

use System\Console\Asset\Exceptions\PackageNotRegisteredException;
use System\Console\Asset\NpmCommand;

class NpmUpdate extends NpmCommand
{
/**
* @var string|null The default command name for lazy loading.
*/
protected static $defaultName = 'npm:update';

/**
* @inheritDoc
*/
protected $description = 'Update Node.js dependencies required for mixed assets';

/**
* @inheritDoc
*/
protected $signature = 'npm:update
{package? : The package name to add configuration for}
{npmArgs?* : Arguments to pass through to the "npm" binary}
{--npm= : Defines a custom path to the "npm" binary}';

/**
* @inheritDoc
*/
public $replaces = [
'mix:update'
];

public function handle(): int
{
$command = ($this->argument('npmArgs')) ?? [];

try {
[$package, $packageJson] = $this->getPackage();
} catch (PackageNotRegisteredException $e) {
array_unshift($command, $this->argument('package'));
}

if (count($command)) {
array_unshift($command, 'npm', 'update', '--');
} else {
array_unshift($command, 'npm', 'update');
}

return $this->npmRun($command, $package['path'] ?? '');
}
}
Loading
Loading