Skip to content

Commit

Permalink
Merge pull request #765 from lucatume/v4-wp-cli-custom-bin
Browse files Browse the repository at this point in the history
feat(Module/WPCLI) support custom bin
  • Loading branch information
lucatume authored Nov 27, 2024
2 parents f89ea80 + f5fa247 commit 13ade12
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 10 deletions.
11 changes: 11 additions & 0 deletions docs/modules/WPCLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ This module should be with [Cest][2] and [Cept][3] test cases.
variable.
* `packages-dir` - the directory to use to store the packages downloaded by the `wp package` command. Equivalent to
setting the `WP_CLI_PACKAGES_DIR` environment variable.
* `bin` - the path to a custom WP-CLI binary.

The following is an example of the module configuration to run WPCLI commands on the `/var/wordpress` directory:

Expand All @@ -67,6 +68,16 @@ modules:
throw: true
```
The following configuration uses a custom WP-CLI binary:
```yaml
modules:
enabled:
lucatume\WPBrowser\Module\WPCLI:
path: /var/wordpress
bin: /usr/local/bin/wp
```
## Methods
The module provides the following methods:
Expand Down
38 changes: 30 additions & 8 deletions src/Module/WPCLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Module;
use lucatume\WPBrowser\Exceptions\InvalidArgumentException;
use lucatume\WPBrowser\Utils\Arr;
use lucatume\WPBrowser\Utils\Filesystem;
use lucatume\WPBrowser\WordPress\CliProcess;
Expand Down Expand Up @@ -40,7 +41,7 @@ class WPCLI extends Module
'color' => true,
'no-color' => true,
'debug' => true,
'quiet' => true
'quiet' => true,
];
/**
* @var array<string>
Expand Down Expand Up @@ -75,7 +76,8 @@ class WPCLI extends Module
* cache-dir?: string,
* config-path?: string,
* custom-shell?: string,
* packages-dir?: string
* packages-dir?: string,
* bin?: string
* }
*/
protected array $config = [
Expand Down Expand Up @@ -129,7 +131,8 @@ public function cli(string|array $command = ['core', 'version'], ?array $env = n
* cache-dir?: string,
* config-path?: string,
* custom-shell?: string,
* packages-dir?: string
* packages-dir?: string,
* bin?: string
* } $config
*/
$config = $this->config;
Expand All @@ -141,7 +144,22 @@ public function cli(string|array $command = ['core', 'version'], ?array $env = n

$command = $this->addStrictOptionsFromConfig($command);

$cliProcess = new CliProcess($command, $config['path'], $env, $input, $config['timeout']);
try {
$cliProcess = new CliProcess(
$command,
$config['path'],
$env,
$input,
$config['timeout'],
$config['bin'] ?? null
);
} catch (\Exception $e) {
throw new ModuleConfigException(
__CLASS__,
$e->getMessage(),
$e
);
}

$this->debugSection('WPCLI command', $cliProcess->getCommandLine());

Expand Down Expand Up @@ -553,7 +571,7 @@ private function validatePath(): void

/**
* @return array{
* WP_CLI_CACHE_DIR: string,
* WP_CLI_CACHE_DIR?: string,
* WP_CLI_CONFIG_PATH?: string,
* WP_CLI_CUSTOM_SHELL?: string,
* WP_CLI_PACKAGES_DIR?: string,
Expand All @@ -569,12 +587,16 @@ private function getDefaultEnv(): array
* cache-dir?: non-empty-string,
* config-path?: non-empty-string,
* custom-shell?: non-empty-string,
* packages-dir?: non-empty-string
* packages-dir?: non-empty-string,
* bin?: string
* } $config Validated config.
*/
$config = $this->config;
$cacheDir = $config['cache-dir'] ?? (Filesystem::cacheDir() . '/wp-cli');
$env['WP_CLI_CACHE_DIR'] = Filesystem::mkdirp($cacheDir);

if (empty($config['bin'])) {
$cacheDir = $config['cache-dir'] ?? (Filesystem::cacheDir() . '/wp-cli');
$env['WP_CLI_CACHE_DIR'] = Filesystem::mkdirp($cacheDir);
}

if (isset($config['config-path'])) {
$env['WP_CLI_CONFIG_PATH'] = $config['config-path'];
Expand Down
27 changes: 25 additions & 2 deletions src/WordPress/CliProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace lucatume\WPBrowser\WordPress;

use lucatume\WPBrowser\Adapters\Symfony\Component\Process\Process;
use lucatume\WPBrowser\Exceptions\InvalidArgumentException;
use lucatume\WPBrowser\Exceptions\RuntimeException;
use lucatume\WPBrowser\Utils\Download;
use lucatume\WPBrowser\Utils\Filesystem;
use lucatume\WPBrowser\Utils\Filesystem as FS;

class CliProcess extends Process
Expand All @@ -22,9 +24,30 @@ public function __construct(
?string $cwd = null,
?array $env = null,
$input = null,
?float $timeout = 60
?float $timeout = 60,
?string $bin = null
) {
$wpCliPhar = self::getWpCliPharPath();
if ($bin === null) {
$wpCliPhar = self::getWpCliPharPath();
} else {
try {
$binAbsolutePath = Filesystem::resolvePath($bin);
} catch (\Exception $e) {
throw new InvalidArgumentException(
'Failed to resolve custom binary path: does it exist?',
$e->getCode(),
$e
);
}

if ($binAbsolutePath === false || !is_executable($binAbsolutePath)) {
throw new InvalidArgumentException(
'WPCLI bin not found or not executable: ' . $binAbsolutePath
);
}
$wpCliPhar = $binAbsolutePath;
}

array_unshift($command, PHP_BINARY, $wpCliPhar);
parent::__construct($command, $cwd, $env, $input, $timeout);
}
Expand Down
4 changes: 4 additions & 0 deletions tests/_data/bins/not-executable
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

echo "This binary was never modded to be executable"
exit 0
4 changes: 4 additions & 0 deletions tests/_data/bins/wp-cli-custom-bin
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env php
<?php
echo "Hello from wp-cli custom binary";
exit(0);
117 changes: 117 additions & 0 deletions tests/unit/lucatume/WPBrowser/Module/WPCLICustomBinaryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace unit\lucatume\WPBrowser\Module;

use Codeception\Exception\ModuleConfigException;
use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
use Codeception\Test\Unit;
use lucatume\WPBrowser\Module\WPCLI;
use lucatume\WPBrowser\Utils\Filesystem;

class WPCLICustomBinaryTest extends Unit
{
private ?string $homeBackup = null;
private string|null|false $envCacheDirValue = null;
private string $wpCliCacheDir;
private string $wpCliCacheDirBackup;

public function setUp(): void
{
parent::setUp();
if (isset($_SERVER['HOME'])) {
$this->homeBackup = $_SERVER['HOME'];
}
$this->wpCliCacheDir = Filesystem::cacheDir() . '/wp-cli';
$this->wpCliCacheDirBackup = dirname($this->wpCliCacheDir) . '/wp-cli-cache-dir-backup';
if (is_dir($this->wpCliCacheDirBackup)) {
Filesystem::rrmdir($this->wpCliCacheDirBackup);
}
if (is_dir($this->wpCliCacheDir)) {
rename($this->wpCliCacheDir, $this->wpCliCacheDirBackup);
}
$this->assertDirectoryDoesNotExist($this->wpCliCacheDir);
}

public function tearDown(): void
{
parent::tearDown();
if ($this->homeBackup !== null) {
$_SERVER['HOME'] = $this->homeBackup;
}
if (is_dir($this->wpCliCacheDir)) {
Filesystem::rrmdir($this->wpCliCacheDir);
}
if (is_dir($this->wpCliCacheDirBackup)) {
rename($this->wpCliCacheDirBackup, $this->wpCliCacheDir);
}
}

public function test_configuration_allows_custom_binary(): void
{
$binary = codecept_data_dir('bins/wp-cli-custom-bin');
$moduleContainer = new ModuleContainer(new Di(), []);

$module = new WPCLI($moduleContainer, [
'path' => 'var/wordpress',
'bin' => $binary,
]);
$module->cli(['core', 'version']);

$this->assertEquals(
'Hello from wp-cli custom binary',
$module->grabLastShellOutput()
);
$this->assertDirectoryDoesNotExist($this->wpCliCacheDir);
}

public function test_configuration_supports_tilde_for_home_in_custom_binary(): void
{
$_SERVER['HOME'] = codecept_data_dir();
$binary = '~/bins/wp-cli-custom-bin';
$binaryPath = codecept_data_dir('bins/wp-cli-custom-bin');
$moduleContainer = new ModuleContainer(new Di(), []);
// Sanity check.
$this->assertEquals(rtrim(codecept_data_dir(), '\\/'), Filesystem::homeDir());

$module = new WPCLI($moduleContainer, [
'path' => 'var/wordpress',
'bin' => $binary,
]);
$module->cli(['core', 'version']);

$this->assertEquals(
'Hello from wp-cli custom binary',
$module->grabLastShellOutput()
);
$this->assertDirectoryDoesNotExist($this->wpCliCacheDir);
}

public function test_throws_if_custom_binary_does_not_exist(): void
{
$binary = codecept_data_dir('bins/not-a-bin');
$moduleContainer = new ModuleContainer(new Di(), []);

$this->expectException(ModuleConfigException::class);

$module = new WPCLI($moduleContainer, [
'path' => 'var/wordpress',
'bin' => $binary,
]);
$module->cli(['core', 'version']);
}

public function test_throws_if_custom_binary_is_not_executable(): void
{
$binary = codecept_data_dir('bins/not-executable');
$moduleContainer = new ModuleContainer(new Di(), []);

$this->expectException(ModuleConfigException::class);

$module = new WPCLI($moduleContainer, [
'path' => 'var/wordpress',
'bin' => $binary,
]);
$module->cli(['core', 'version']);
}
}
75 changes: 75 additions & 0 deletions tests/unit/lucatume/WPBrowser/WordPress/CliProcessTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php


namespace Unit\lucatume\WPBrowser\WordPress;

use lucatume\WPBrowser\Exceptions\InvalidArgumentException;
use lucatume\WPBrowser\Utils\Filesystem;
use lucatume\WPBrowser\WordPress\CliProcess;

class CliProcessTest extends \Codeception\Test\Unit
{
private ?string $homeBackup = null;

public function setUp(): void
{
parent::setUp();
if (isset($_SERVER['HOME'])) {
$this->homeBackup = $_SERVER['HOME'];
}
}

public function tearDown(): void
{
parent::tearDown();
if ($this->homeBackup !== null) {
$_SERVER['HOME'] = $this->homeBackup;
}
}

public function test_construct_with_custom_binary(): void
{
$binary = codecept_data_dir('bins/wp-cli-custom-bin');

$cliProcess = new CliProcess(['core', 'version'], null, null, null, null, $binary);

$this->assertEquals(
escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($binary) . " 'core' 'version'",
$cliProcess->getCommandLine()
);
}

public function test_throws_if_custom_binary_does_not_exist(): void
{
$binary = codecept_data_dir('bins/not-a-bin');

$this->expectException(InvalidArgumentException::class);

$cliProcess = new CliProcess(['core', 'version'], null, null, null, null, $binary);
}

public function test_throws_if_custom_binary_is_not_executable(): void
{
$binary = codecept_data_dir('bins/not-executable');

$this->expectException(InvalidArgumentException::class);

$cliProcess = new CliProcess(['core', 'version'], null, null, null, null, $binary);
}

public function test_tilde_for_home_dir_is_supported_in_custom_binary_path(): void
{
$_SERVER['HOME'] = codecept_data_dir();
$binary = '~/bins/wp-cli-custom-bin';
$binaryAbsolutePath = codecept_data_dir('bins/wp-cli-custom-bin');
// Sanity check.
$this->assertEquals(rtrim(codecept_data_dir(), '\\/'), Filesystem::homeDir());

$cliProcess = new CliProcess(['core', 'version'], null, null, null, null, $binary);

$this->assertEquals(
escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($binaryAbsolutePath) . " 'core' 'version'",
$cliProcess->getCommandLine()
);
}
}

0 comments on commit 13ade12

Please sign in to comment.