Skip to content

Commit

Permalink
Add compatibility with Yarn 2
Browse files Browse the repository at this point in the history
  • Loading branch information
francoispluchino committed Aug 9, 2021
1 parent aeae35a commit a3ad5d8
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 17 deletions.
38 changes: 26 additions & 12 deletions Asset/AbstractAssetManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\VersionParser;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
Expand Down Expand Up @@ -62,6 +61,11 @@ abstract class AbstractAssetManager implements AssetManagerInterface
*/
protected $updatable = true;

/**
* @var null|string
*/
private $version = '';

/**
* Constructor.
*
Expand Down Expand Up @@ -90,9 +94,7 @@ public function __construct(
*/
public function isAvailable()
{
$this->executor->execute($this->getVersionCommand(), $version);

return '' !== trim($version);
return null !== $this->getVersion();
}

/**
Expand Down Expand Up @@ -160,19 +162,18 @@ public function isValidForUpdate()
*/
public function validate()
{
$this->executor->execute($this->getVersionCommand(), $version);
$version = trim($version);
$version = $this->getVersion();
$constraintVersion = $this->config->get('manager-version');

if ('' === $version) {
if (null === $version) {
throw new RuntimeException(sprintf('The binary of "%s" must be installed', $this->getName()));
}

if ($constraintVersion) {
$parser = new VersionParser();
$constraint = $parser->parseConstraints($constraintVersion);

if (!$constraint->matches(new Constraint('=', $version))) {
if (!$constraint->matches($parser->parseConstraints($version))) {
throw new RuntimeException(sprintf('The installed %s version "%s" doesn\'t match with the constraint version "%s"', $this->getName(), $version, $constraintVersion));
}
}
Expand Down Expand Up @@ -232,9 +233,9 @@ protected function actionWhenComposerDependenciesAreAlreadyInstalled($names)
/**
* Build the command with binary and command options.
*
* @param string $defaultBin The default binary of command if option isn't defined
* @param string $action The command action to retrieve the options in config
* @param string $command The command
* @param string $defaultBin The default binary of command if option isn't defined
* @param string $action The command action to retrieve the options in config
* @param string|string[] $command The command
*
* @return string
*/
Expand All @@ -245,11 +246,24 @@ protected function buildCommand($defaultBin, $action, $command)
$gOptions = trim($this->config->get('manager-options', ''));
$options = trim($this->config->get('manager-'.$action.'-options', ''));

return $bin.' '.$command
return $bin.' '.implode(' ', (array) $command)
.(empty($gOptions) ? '' : ' '.$gOptions)
.(empty($options) ? '' : ' '.$options);
}

/**
* @return null|string
*/
protected function getVersion()
{
if ('' === $this->version) {
$this->executor->execute($this->getVersionCommand(), $version);
$this->version = '' !== trim($version) ? trim($version) : null;
}

return $this->version;
}

/**
* Get the command to retrieve the version.
*
Expand Down
35 changes: 32 additions & 3 deletions Asset/YarnManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Foxy\Asset;

use Composer\Semver\VersionParser;

/**
* Yarn Manager.
*
Expand Down Expand Up @@ -47,7 +49,11 @@ public function isInstalled()
*/
public function isValidForUpdate()
{
$cmd = $this->buildCommand('yarn', 'check', 'check --non-interactive');
if ($this->isYarnNext()) {
return true;
}

$cmd = $this->buildCommand('yarn', 'check', $this->mergeInteractiveCommand(array('check')));

return 0 === $this->executor->execute($cmd);
}
Expand All @@ -65,14 +71,37 @@ protected function getVersionCommand()
*/
protected function getInstallCommand()
{
return $this->buildCommand('yarn', 'install', 'install --non-interactive');
return $this->buildCommand('yarn', 'install', $this->mergeInteractiveCommand(array('install')));
}

/**
* {@inheritdoc}
*/
protected function getUpdateCommand()
{
return $this->buildCommand('yarn', 'update', 'upgrade --non-interactive');
$commandName = $this->isYarnNext() ? 'up' : 'upgrade';

return $this->buildCommand('yarn', 'update', $this->mergeInteractiveCommand(array($commandName)));
}

/**
* @return bool
*/
private function isYarnNext()
{
$version = $this->getVersion();
$parser = new VersionParser();
$constraint = $parser->parseConstraints('>=2.0.0');

return $constraint->matches($parser->parseConstraints($version));
}

private function mergeInteractiveCommand(array $command)
{
if (!$this->isYarnNext()) {
$command[] = '--non-interactive';
}

return $command;
}
}
6 changes: 5 additions & 1 deletion Tests/Asset/YarnAssetManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ final class YarnAssetManagerTest extends AbstractAssetManagerTest
*/
public function actionForTestRunForInstallCommand($action)
{
$this->executor->addExpectedValues(0, '1.0.0');

if ('update' === $action) {
$this->executor->addExpectedValues(0, 'CHECK OUTPUT');
$this->executor->addExpectedValues(0, '1.0.0');
$this->executor->addExpectedValues(0, '1.0.0');
$this->executor->addExpectedValues(0, 'CHECK OUTPUT');
}
}
Expand Down Expand Up @@ -86,6 +89,7 @@ protected function getValidUpdateCommand()
*/
protected function actionForTestAddDependenciesForUpdateCommand()
{
$this->executor->addExpectedValues(0, '1.0.0');
$this->executor->addExpectedValues(0, 'CHECK OUTPUT');
}
}
93 changes: 93 additions & 0 deletions Tests/Asset/YarnNextAssetManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

/*
* This file is part of the Foxy package.
*
* (c) François Pluchino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Foxy\Tests\Asset;

use Foxy\Asset\YarnManager;

/**
* Yarn Next asset manager tests.
*
* @author François Pluchino <[email protected]>
*
* @internal
*/
final class YarnNextAssetManagerTest extends AbstractAssetManagerTest
{
/**
* {@inheritdoc}
*/
public function actionForTestRunForInstallCommand($action)
{
$this->executor->addExpectedValues(0, '2.0.0');

if ('update' === $action) {
$this->executor->addExpectedValues(0, '2.0.0');
}
}

/**
* {@inheritdoc}
*/
protected function getManager()
{
return new YarnManager($this->io, $this->config, $this->executor, $this->fs, $this->fallback);
}

/**
* {@inheritdoc}
*/
protected function getValidName()
{
return 'yarn';
}

/**
* {@inheritdoc}
*/
protected function getValidLockPackageName()
{
return 'yarn.lock';
}

/**
* {@inheritdoc}
*/
protected function getValidVersionCommand()
{
return 'yarn --version';
}

/**
* {@inheritdoc}
*/
protected function getValidInstallCommand()
{
return 'yarn install';
}

/**
* {@inheritdoc}
*/
protected function getValidUpdateCommand()
{
return 'yarn up';
}

/**
* {@inheritdoc}
*/
protected function actionForTestAddDependenciesForUpdateCommand()
{
$this->executor->addExpectedValues(0, '2.0.0');
$this->executor->addExpectedValues(0, 'CHECK OUTPUT');
}
}
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a3ad5d8

Please sign in to comment.