From b10fcd67bd900bbc919b7a54d5bcfa481cde9b47 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Fri, 30 Sep 2022 15:56:34 -0400 Subject: [PATCH 01/15] Stubbing out rsyncing --- .../testing/class-installation-manager.php | 3 +- .../concerns/trait-rsync-installation.php | 114 ++++++++++++++++++ tests/bootstrap.php | 6 +- 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/mantle/testing/concerns/trait-rsync-installation.php diff --git a/src/mantle/testing/class-installation-manager.php b/src/mantle/testing/class-installation-manager.php index 710d54f68..6e1f6853d 100644 --- a/src/mantle/testing/class-installation-manager.php +++ b/src/mantle/testing/class-installation-manager.php @@ -13,7 +13,8 @@ * Installation Manager */ class Installation_Manager { - use Singleton; + use Concerns\Rsync_Installation, + Singleton; /** * Callbacks for before installation. diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php new file mode 100644 index 000000000..5b04a354e --- /dev/null +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -0,0 +1,114 @@ +rsync_to = $to ?: $this->get_installation_path() . '/wp-content/plugins/plugin'; + $this->rsync_from = $from ?: getcwd(); + + return $this; + } + + /** + * Rsync the code base to be located underneath a WordPress installation if it + * isn't already. + * + * @param string $to Location to rsync to. + * @param string $from Location to rsync from. + * @return static + */ + public function maybe_rsync( string $to = null, string $from = null ) { + // Check if we are under an existing WordPress installation. + if ( $this->is_within_wordpress_install() ) { + return $this; + } + + return $this->rsync( $to, $from ); + } + + /** + * Maybe rsync the codebase as a plugin within WordPress. + * + * @param string $name Name of the plugin to use. + * @param string $from Location to rsync from + */ + public function maybe_rsync_plugin( string $name = 'plugin', string $from = null ) { + // Check if we are under an existing WordPress installation. + if ( $this->is_within_wordpress_install() ) { + return $this; + } + + return $this->rsync( "plugins/{$name}", $from ); + } + + /** + * Maybe rsync the codebase as a theme within WordPress. + * + * @param string $name Name of the plugin to use. + * @param string $from Location to rsync from + */ + public function maybe_rsync_theme( string $name = 'theme', string $from = null ) { + // Check if we are under an existing WordPress installation. + if ( $this->is_within_wordpress_install() ) { + return $this; + } + + return $this->rsync( "themes/{$name}", $from ); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 54a9e82e0..985f258ec 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,4 +10,8 @@ define( 'MANTLE_PHPUNIT_INCLUDES_PATH', __DIR__ . '/includes' ); define( 'MANTLE_PHPUNIT_TEMPLATE_PATH', __DIR__ . '/template-parts' ); -\Mantle\Testing\install(); +\Mantle\Testing\manager() + ->maybe_rsync() + ->install(); + +// \Mantle\Testing\install(); From 685ae2c6792e896ec60398a9f1e808785a82a407 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Fri, 7 Oct 2022 16:50:11 -0400 Subject: [PATCH 02/15] WIP --- .../testing/class-installation-manager.php | 4 + .../concerns/trait-rsync-installation.php | 127 +++++++++++++++--- tests/.DS_Store | Bin 6148 -> 10244 bytes tests/bootstrap.php | 2 +- 4 files changed, 111 insertions(+), 22 deletions(-) diff --git a/src/mantle/testing/class-installation-manager.php b/src/mantle/testing/class-installation-manager.php index 6e1f6853d..c92c1809d 100644 --- a/src/mantle/testing/class-installation-manager.php +++ b/src/mantle/testing/class-installation-manager.php @@ -98,6 +98,10 @@ public function on( string $hook, ?callable $callback, int $priority = 10, int $ * @return static */ public function install() { + if ( $this->rsync_to ) { + $this->rsync_before_install(); + } + require_once __DIR__ . '/core-polyfill.php'; foreach ( $this->before_install_callbacks as $callback ) { diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php index 5b04a354e..c6b3a39b6 100644 --- a/src/mantle/testing/concerns/trait-rsync-installation.php +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -7,6 +7,8 @@ namespace Mantle\Testing\Concerns; +use Mantle\Testing\Utils; + /** * Trait to manage rsync-ing the codebase to live within a WordPress * installation. @@ -32,25 +34,6 @@ trait Rsync_Installation { */ protected ?string $rsync_from = null; - /** - * Retrieve the default installation path to rsync to. - * - * @return string - */ - protected function get_installation_path(): string { - return getenv( 'WP_CORE_DIR' ) ?: sys_get_temp_dir() . '/wordpress'; - } - - /** - * Check if the current installation is underneath an existing WordPress - * installation. - * - * @return bool - */ - protected function is_within_wordpress_install(): bool { - return false !== strpos( __DIR__, '/wp-content/' ); - } - /** * Rsync the code base to be located under a valid WordPress installation. * @@ -86,7 +69,7 @@ public function maybe_rsync( string $to = null, string $from = null ) { * Maybe rsync the codebase as a plugin within WordPress. * * @param string $name Name of the plugin to use. - * @param string $from Location to rsync from + * @param string $from Location to rsync from. */ public function maybe_rsync_plugin( string $name = 'plugin', string $from = null ) { // Check if we are under an existing WordPress installation. @@ -101,7 +84,7 @@ public function maybe_rsync_plugin( string $name = 'plugin', string $from = null * Maybe rsync the codebase as a theme within WordPress. * * @param string $name Name of the plugin to use. - * @param string $from Location to rsync from + * @param string $from Location to rsync from. */ public function maybe_rsync_theme( string $name = 'theme', string $from = null ) { // Check if we are under an existing WordPress installation. @@ -111,4 +94,106 @@ public function maybe_rsync_theme( string $name = 'theme', string $from = null ) return $this->rsync( "themes/{$name}", $from ); } + + /** + * Retrieve the default installation path to rsync to. + * + * @return string + */ + protected function get_installation_path(): string { + return getenv( 'WP_CORE_DIR' ) ?: sys_get_temp_dir() . '/wordpress'; + } + + /** + * Check if the current installation is underneath an existing WordPress + * installation. + * + * @return bool + */ + protected function is_within_wordpress_install(): bool { + return false !== strpos( __DIR__, '/wp-content/' ); + } + + /** + * Rsync the codebase before installation. + * + * @return void + */ + protected function rsync_before_install() { + require_once __DIR__ . '/../class-utils.php'; + + $base_install_path = $this->get_installation_path(); + + // Normalize the rsync destination. + $this->rsync_to = is_dir( $this->rsync_to ) ? $this->rsync_to : "$base_install_path/wp-content/{$this->rsync_to}"; + + defined( 'WP_TESTS_INSTALL_PATH' ) || define( 'WP_TESTS_INSTALL_PATH', $base_install_path ); + + // TEMP + system( "rm -rf {$base_install_path}" ); + + // Install WordPress at the base installation path if it doesn't exist yet. + if ( ! is_dir( $base_install_path ) ) { + echo "Installing WordPress at [{$base_install_path}]...\n"; + + + // Create the installation directory. + if ( ! is_dir( $base_install_path ) && ! mkdir( $base_install_path, 0777, true ) ) { + throw new \RuntimeException( "Unable to create directory [{$base_install_path}]." ); + } + + $cmd = sprintf( + 'export WP_CORE_DIR=%s && curl -s %s | bash -s %s %s %s %s %s %s', + $base_install_path, + 'https://raw.githubusercontent.com/alleyinteractive/mantle-ci/HEAD/install-wp-tests.sh', + // 'https://raw.githubusercontent.com/alleyinteractive/mantle-ci/debug/install-wp-tests.sh', + // 'http://localhost:3030/install-wp-tests.sh', + Utils::shell_safe( defined( 'DB_NAME' ) ? DB_NAME : Utils::env( 'WP_DB_NAME', 'wordpress_unit_tests' ) ), + Utils::shell_safe( defined( 'DB_USER' ) ? DB_USER : Utils::env( 'WP_DB_USER', 'root' ) ), + Utils::shell_safe( defined( 'DB_PASSWORD' ) ? DB_PASSWORD : Utils::env( 'WP_DB_PASSWORD', 'root' ) ), + Utils::shell_safe( defined( 'DB_HOST' ) ? DB_HOST : Utils::env( 'WP_DB_HOST', 'localhost' ) ), + Utils::shell_safe( Utils::env( 'WP_VERSION', 'latest' ) ), + Utils::shell_safe( Utils::env( 'WP_SKIP_DB_CREATE', 'false' ) ), + ); + + $resp = system( $cmd, $retval ); + // $resp = system( $cmd, $retval ); + + dd('RESP', $cmd, $resp); + + if ( 0 !== $retval ) { + echo "\n🚨 Error installing WordPress!\nResponse from installation command:\n\n$resp\n" . PHP_EOL; + exit( 1 ); + } + + echo "WordPress installed at [{$base_install_path}]...\n"; + } else { + echo "WordPress already installed at [{$base_install_path}]...\n"; + } + + echo "Rsyncing the code from [{$this->rsync_from}] to [{$this->rsync_to}]...\n"; + + if ( ! is_dir( $this->rsync_to ) && ! mkdir( $this->rsync_to, 0777, true ) ) { + throw new \RuntimeException( "Unable to create destination directory [{$this->rsync_to}]." ); + } + + $cmd = implode( + ' ', + [ + 'rsync -aWq', + '--no-compress', + '--exclude .npm', + '--exclude .git', + '--exclude node_modules', + '--exclude .composer', + '--exclude .phpcs', + '--exclude .buddy-tests', + "{$this->rsync_from} {$this->rsync_to}", + ] + ); + + dd('CMD', $cmd); + + exit; + } } diff --git a/tests/.DS_Store b/tests/.DS_Store index 1659230e9ae9b4ae2524bccddeb838cfd7d89a15..4e45eb3857e6cc4653c82359dc84524735eee257 100644 GIT binary patch literal 10244 zcmeI1O>7%Q6vyA@!`_XdG7?BlRl!Oe3Q~|9idt@UL)rr$BC0DQK}l@Ko7k$o>#o;v zQ54BVh*O1%#3^v#K#0VJE5`^b=%oT7fjDqM9Jp}pu~Ofg-HhMthn))&m1d*e+3ft^ zd%t}%J3F%m0As1&SOl;Ez{H)(;uCmC*{GiO#5NUOc^69q?EwPlwYL^48(ycIQ0ogi z13Cjb13Cjb13Cl$hYa95n>Mo$minkOpfjK|ATvPYgN-|t<)|Enr5HN!AeI1F&fsOS z;W@4YgpD1Q<)|Enr7%UG;p)MNOpR!XVT9&bZ<8F$a#Rk(GBgJxGzTM!Y(y&*LqtbA zTgbsEhowI14Co9bGeB$i9MqtPe@=4!e(FNJzT+(~*V|qlubcPQU;pW_clTma)0n8~ zHu-mg61sp{*g%pEXo91DMX>hOTF&4$Bm=YWcq4*zg&JRs8aa&ZfeV|^f-RLG_oKK+ zR?itOZ%GEl2dBu=q;TXTjvmsq-9me8;ybw>fLs$7nDkW7*o?Tv$?!!%@wS|iGuZhrRfbSK`rR_ zmTLZb@pPrtaOyRGwbclkR~`3K+u3&9xBWM3f#bhN;;Ww5MnQO9tH0B72J6MAU-R6c z)^Z(R_zQhpTWz@wZ?NR`-9}I7Bj@6Lr4}^NkNJGL_6ywsSf;gJJh`*8SSl^pFQ0pL zcfsB{e;&_YIeTt**D}rdGncQd^*{V%@AI$rzdrc>2Vn(9G~0rw!vE#*F8NHRMQyP9 zwR9D4vQHn#CQI?h8*RK&X||9$#ou~6@%eaxQU%VfUcUy#v!lc4ELXTf87b zia|@IIJ=jv3=}8V(lng${wc|r@WtuI=~ON; z&`u+f7oR%JeS5o=>@f)FU?KbXJ+-W1-Ff4@$ z9!Nsh#pihZhrUw15M2{?w{>e`y1O;-^4TF>Oa|?j#!C>-32?dVb_Lci(Obmaybe_rsync() + ->maybe_rsync_plugin() ->install(); // \Mantle\Testing\install(); From 907d430597385234189d975fb2f9959182b34eff Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Tue, 11 Oct 2022 17:19:16 -0400 Subject: [PATCH 03/15] Adding support for rsyncing a plugin/theme --- composer.json | 1 + .../testing/class-installation-manager.php | 39 +++++- src/mantle/testing/class-utils.php | 103 ++++++++++++++- .../concerns/trait-output-messages.php | 96 ++++++++++++++ .../concerns/trait-rsync-installation.php | 121 ++++++++++-------- src/mantle/testing/core-polyfill.php | 24 ++++ src/mantle/testing/wordpress-bootstrap.php | 62 +++++---- tests/bootstrap.php | 2 - 8 files changed, 360 insertions(+), 88 deletions(-) create mode 100644 src/mantle/testing/concerns/trait-output-messages.php diff --git a/composer.json b/composer.json index 3c8c699ea..82c3754b3 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "monolog/monolog": "^2.7", "nesbot/carbon": "^2.53", "nette/php-generator": "^3.6", + "nunomaduro/termwind": "^1.14", "psr/container": "^1.1.1 || ^2.0.1", "psr/log": "^1.0.1 || ^2.0 || ^3.0", "symfony/finder": "^5.3", diff --git a/src/mantle/testing/class-installation-manager.php b/src/mantle/testing/class-installation-manager.php index c92c1809d..69edc305e 100644 --- a/src/mantle/testing/class-installation-manager.php +++ b/src/mantle/testing/class-installation-manager.php @@ -98,21 +98,21 @@ public function on( string $hook, ?callable $callback, int $priority = 10, int $ * @return static */ public function install() { + require_once __DIR__ . '/core-polyfill.php'; + if ( $this->rsync_to ) { $this->rsync_before_install(); } - require_once __DIR__ . '/core-polyfill.php'; - foreach ( $this->before_install_callbacks as $callback ) { $callback(); } try { - require_once __DIR__ . '/wordpress-bootstrap.php'; + require_once $this->bootstrap_file_path(); } catch ( \Throwable $throwable ) { - echo "ERROR: Failed to load WordPress!\n"; - echo "{$throwable}\n"; // phpcs:ignore + Utils::error( '🚨 Failed to load the WordPress installation. Exception thrown:' ); + Utils::code( $throwable->getMessage() ); exit( 1 ); } @@ -122,4 +122,33 @@ public function install() { return $this; } + + /** + * Retrieve the bootstrap file path. + * + * @return string + */ + protected function bootstrap_file_path(): string { + if ( defined( 'WP_TESTS_BOOTSTRAP_FILE' ) ) { + return WP_TESTS_BOOTSTRAP_FILE; + } + + if ( ! $this->rsync_to ) { + return __DIR__ . '/wordpress-bootstrap.php'; + } + + $base_path = [ + $this->rsync_to . '/src/mantle/testing/wordpress-bootstrap.php', + $this->rsync_to . '/vendor/alleyinteractive/mantle-framework/src/mantle/testing/wordpress-bootstrap.php', + $this->rsync_to . '/vendor/mantle-framework/testing/src/mantle/testing/wordpress-bootstrap.php', + ]; + + foreach ( $base_path as $path ) { + if ( file_exists( $path ) ) { + return $path; + } + } + + return __DIR__ . '/wordpress-bootstrap.php'; + } } diff --git a/src/mantle/testing/class-utils.php b/src/mantle/testing/class-utils.php index 7012bf7d5..9ff61efa5 100644 --- a/src/mantle/testing/class-utils.php +++ b/src/mantle/testing/class-utils.php @@ -9,12 +9,22 @@ use Mantle\Testing\Doubles\Spy_REST_Server; +use function Termwind\render; + +if ( class_exists( Utils::class ) ) { + return; +} + +require_once __DIR__ . '/concerns/trait-output-messages.php'; + /** * Assorted testing utilities. * * A fork of https://github.com/WordPress/wordpress-develop/blob/master/tests/phpunit/includes/utils.php. */ class Utils { + use Concerns\Output_Messages; + /** * Default database name. * @@ -62,6 +72,7 @@ public static function get_echo( $callable, $args = [] ) { call_user_func_array( $callable, $args ); return ob_get_clean(); } + /** * Unregister a post status. * @@ -197,7 +208,7 @@ public static function setup_configuration(): void { global $table_prefix; // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound - defined( 'ABSPATH' ) || define( 'ABSPATH', preg_replace( '#/wp-content/.*$#', '/', __DIR__ ) ); + defined( 'ABSPATH' ) || define( 'ABSPATH', ensure_trailingslash( preg_replace( '#/wp-content/.*$#', '/', __DIR__ ) ) ); defined( 'WP_DEBUG' ) || define( 'WP_DEBUG', true ); defined( 'DB_NAME' ) || define( 'DB_NAME', static::DEFAULT_DB_NAME ); @@ -254,4 +265,94 @@ public static function env( string $variable, $default ) { public static function shell_safe( string $string ): string { return empty( trim( $string ) ) ? "''" : $string; } + + /** + * Install a WordPress codebase through a shell script. + * + * This installs the WordPress codebase in the specified directory. It does + * not install the WordPress database. + * + * @param string $directory Directory to install WordPress in. + */ + public static function install_wordpress( string $directory ): void { + $command = sprintf( + 'export WP_CORE_DIR=%s && curl -s %s | bash -s %s %s %s %s %s %s', + $directory, + 'https://raw.githubusercontent.com/alleyinteractive/mantle-ci/HEAD/install-wp-tests.sh', + static::shell_safe( defined( 'DB_NAME' ) ? DB_NAME : static::env( 'WP_DB_NAME', 'wordpress_unit_tests' ) ), + static::shell_safe( defined( 'DB_USER' ) ? DB_USER : static::env( 'WP_DB_USER', 'root' ) ), + static::shell_safe( defined( 'DB_PASSWORD' ) ? DB_PASSWORD : static::env( 'WP_DB_PASSWORD', 'root' ) ), + static::shell_safe( defined( 'DB_HOST' ) ? DB_HOST : static::env( 'WP_DB_HOST', 'localhost' ) ), + static::shell_safe( static::env( 'WP_VERSION', 'latest' ) ), + static::shell_safe( static::env( 'WP_SKIP_DB_CREATE', 'false' ) ), + ); + + $output = static::command( $command, $retval ); + + if ( 0 !== $retval ) { + static::error( '🚨 Error installing WordPress! Output from installation:', 'Install Rsync' ); + static::code( $output ); + exit( 1 ); + } + } + + /** + * Run a system command and return the output. + * + * @param string|string[] $command Command to run. + * @param int $exit_code Exit code. + * @return string[] + */ + public static function command( $command, &$exit_code = null ) { + // Display the command if in debug mode. + if ( + ! empty( + array_intersect( + (array) $_SERVER['argv'] ?? [], // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + [ + '--debug', + '--verbose', + '-v', + ], + ) + ) + ) { + render( + '
+ Running: + ' . implode( ' ', (array) $command ) . ' +
' + ); + } + + if ( is_array( $command ) ) { + $command = implode( ' ', $command ); + } + + exec( $command, $output, $exit_code ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec + + return $output; + } + + /** + * Ensure that Composer is loaded for the current environment. + */ + public static function ensure_composer_loaded() { + if ( class_exists( 'Composer\Autoload\ClassLoader' ) ) { + return; + } + + $paths = [ + preg_replace( '#/vendor/.*$#', '/vendor/autoload.php', __DIR__ ), + __DIR__ . '/../../../vendor/autoload.php', + __DIR__ . '/../../vendor/autoload.php', + ]; + + foreach ( $paths as $path ) { + if ( ! is_dir( $path ) && file_exists( $path ) ) { + require_once $path; + return; + } + } + } } diff --git a/src/mantle/testing/concerns/trait-output-messages.php b/src/mantle/testing/concerns/trait-output-messages.php new file mode 100644 index 000000000..3b9893a55 --- /dev/null +++ b/src/mantle/testing/concerns/trait-output-messages.php @@ -0,0 +1,96 @@ + +
%s
+ %s + ', + $parent_classes, + $prefix_color, + $message_color, + $prefix, + $message, + ) + ); + } + + /** + * Output a info message to the console. + * + * @param string $message Message to output. + * @param string $prefix Prefix to output. + * @return void + */ + public static function info( string $message, $prefix = 'Install' ): void { + static::message( $prefix, 'yellow-600', $message ); + } + + /** + * Output a success message to the console. + * + * @param string $message Message to output. + * @param string $prefix Prefix to output. + * @return void + */ + public static function success( string $message, $prefix = 'Install' ): void { + static::message( $prefix, 'lime-600', $message ); + } + + /** + * Output a error message to the console. + * + * @param string $message Message to output. + * @param string $prefix Prefix to output. + * @return void + */ + public static function error( string $message, $prefix = 'Install' ): void { + static::message( $prefix, 'red-800', $message, 'red-100', 'pt-1' ); + } + + /** + * Display a formatted code block. + * + * @link https://github.com/nunomaduro/termwind#code + * + * @param string|string[] $code Code to display. + * @return void + */ + public static function code( $code ): void { + if ( is_array( $code ) ) { + $code = implode( PHP_EOL, $code ); + } + + render( "
{$code}
" ); + } +} diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php index c6b3a39b6..dedc0bf47 100644 --- a/src/mantle/testing/concerns/trait-rsync-installation.php +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -2,6 +2,8 @@ /** * Rsync_Installation trait file * + * phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound + * * @package Mantle */ @@ -37,13 +39,15 @@ trait Rsync_Installation { /** * Rsync the code base to be located under a valid WordPress installation. * + * By default, the codebase will be rsynced to the `wp-content` directory. + * * @param string $to Location to rsync to within `wp-content`. * @param string $from Location to rsync from. * @return static */ public function rsync( string $to = null, string $from = null ) { $this->rsync_to = $to ?: $this->get_installation_path() . '/wp-content/plugins/plugin'; - $this->rsync_from = $from ?: getcwd(); + $this->rsync_from = $from ?: getcwd() . '/'; return $this; } @@ -68,31 +72,33 @@ public function maybe_rsync( string $to = null, string $from = null ) { /** * Maybe rsync the codebase as a plugin within WordPress. * - * @param string $name Name of the plugin to use. + * By default, the from path will be rsynced to `wp-content/plugins/{directory_name}`. + * + * @param string $name Name of the plugin folder, optional. * @param string $from Location to rsync from. */ - public function maybe_rsync_plugin( string $name = 'plugin', string $from = null ) { - // Check if we are under an existing WordPress installation. - if ( $this->is_within_wordpress_install() ) { - return $this; + public function maybe_rsync_plugin( string $name = null, string $from = null ) { + if ( ! $name ) { + $name = basename( getcwd() ); } - return $this->rsync( "plugins/{$name}", $from ); + return $this->maybe_rsync( "plugins/{$name}/", $from ); } /** * Maybe rsync the codebase as a theme within WordPress. * - * @param string $name Name of the plugin to use. + * By default, the from path will be rsynced to `wp-content/themes/{directory_name}`. + * + * @param string $name Name of the theme folder, optional. * @param string $from Location to rsync from. */ - public function maybe_rsync_theme( string $name = 'theme', string $from = null ) { - // Check if we are under an existing WordPress installation. - if ( $this->is_within_wordpress_install() ) { - return $this; + public function maybe_rsync_theme( string $name = null, string $from = null ) { + if ( ! $name ) { + $name = basename( getcwd() ); } - return $this->rsync( "themes/{$name}", $from ); + return $this->maybe_rsync( 'themes', $from ); } /** @@ -117,7 +123,8 @@ protected function is_within_wordpress_install(): bool { /** * Rsync the codebase before installation. * - * @return void + * This allows the plugin/theme project to properly situate itself within a + * WordPress installation without needing to rsync it manually. */ protected function rsync_before_install() { require_once __DIR__ . '/../class-utils.php'; @@ -127,58 +134,56 @@ protected function rsync_before_install() { // Normalize the rsync destination. $this->rsync_to = is_dir( $this->rsync_to ) ? $this->rsync_to : "$base_install_path/wp-content/{$this->rsync_to}"; + // Define the constants relative to where the codebase is being rsynced to. defined( 'WP_TESTS_INSTALL_PATH' ) || define( 'WP_TESTS_INSTALL_PATH', $base_install_path ); - - // TEMP - system( "rm -rf {$base_install_path}" ); + defined( 'WP_TESTS_CONFIG_FILE_PATH' ) || define( 'WP_TESTS_CONFIG_FILE_PATH', "{$base_install_path}/wp-tests-config.php" ); + defined( 'ABSPATH' ) || define( 'ABSPATH', ensure_trailingslash( $base_install_path ) ); // Install WordPress at the base installation path if it doesn't exist yet. if ( ! is_dir( $base_install_path ) ) { - echo "Installing WordPress at [{$base_install_path}]...\n"; - - - // Create the installation directory. - if ( ! is_dir( $base_install_path ) && ! mkdir( $base_install_path, 0777, true ) ) { - throw new \RuntimeException( "Unable to create directory [{$base_install_path}]." ); - } - - $cmd = sprintf( - 'export WP_CORE_DIR=%s && curl -s %s | bash -s %s %s %s %s %s %s', - $base_install_path, - 'https://raw.githubusercontent.com/alleyinteractive/mantle-ci/HEAD/install-wp-tests.sh', - // 'https://raw.githubusercontent.com/alleyinteractive/mantle-ci/debug/install-wp-tests.sh', - // 'http://localhost:3030/install-wp-tests.sh', - Utils::shell_safe( defined( 'DB_NAME' ) ? DB_NAME : Utils::env( 'WP_DB_NAME', 'wordpress_unit_tests' ) ), - Utils::shell_safe( defined( 'DB_USER' ) ? DB_USER : Utils::env( 'WP_DB_USER', 'root' ) ), - Utils::shell_safe( defined( 'DB_PASSWORD' ) ? DB_PASSWORD : Utils::env( 'WP_DB_PASSWORD', 'root' ) ), - Utils::shell_safe( defined( 'DB_HOST' ) ? DB_HOST : Utils::env( 'WP_DB_HOST', 'localhost' ) ), - Utils::shell_safe( Utils::env( 'WP_VERSION', 'latest' ) ), - Utils::shell_safe( Utils::env( 'WP_SKIP_DB_CREATE', 'false' ) ), + Utils::info( + "Installating WordPress at {$base_install_path} ...", + 'Install Rsync' ); - $resp = system( $cmd, $retval ); - // $resp = system( $cmd, $retval ); - - dd('RESP', $cmd, $resp); + // Create the installation directory. + if ( ! is_dir( $base_install_path ) && ! mkdir( $base_install_path, 0777, true ) ) { // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.directory_mkdir + Utils::error( + "Unable to create the WordPress installation directory at {$base_install_path}", + 'Install Rsync' + ); - if ( 0 !== $retval ) { - echo "\n🚨 Error installing WordPress!\nResponse from installation command:\n\n$resp\n" . PHP_EOL; exit( 1 ); } - echo "WordPress installed at [{$base_install_path}]...\n"; + Utils::install_wordpress( $base_install_path ); + + Utils::success( + "WordPress installed at {$base_install_path}", + 'Install Rsync' + ); } else { - echo "WordPress already installed at [{$base_install_path}]...\n"; + Utils::info( + "WordPress already installed at {$base_install_path}", + 'Install Rsync' + ); } - echo "Rsyncing the code from [{$this->rsync_from}] to [{$this->rsync_to}]...\n"; + Utils::info( + "Rsyncing {$this->rsync_from} to {$this->rsync_to}...", + 'Install Rsync' + ); + + if ( ! is_dir( $this->rsync_to ) && ! mkdir( $this->rsync_to, 0777, true ) ) { // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.directory_mkdir + Utils::error( + "Unable to create destination directory [{$this->rsync_to}]." + ); - if ( ! is_dir( $this->rsync_to ) && ! mkdir( $this->rsync_to, 0777, true ) ) { - throw new \RuntimeException( "Unable to create destination directory [{$this->rsync_to}]." ); + exit( 1 ); } - $cmd = implode( - ' ', + // Rsync the from folder to the destination. + $output = Utils::command( [ 'rsync -aWq', '--no-compress', @@ -189,11 +194,21 @@ protected function rsync_before_install() { '--exclude .phpcs', '--exclude .buddy-tests', "{$this->rsync_from} {$this->rsync_to}", - ] + ], + $retval ); - dd('CMD', $cmd); + if ( 0 !== $retval ) { + Utils::error( '🚨 Error installing rsyncing! Output from command:', 'Install Rsync' ); + Utils::code( $output ); + exit( 1 ); + } + + Utils::success( + "Rsynced to {$this->rsync_to} and changed working directory.", + 'Install Rsync' + ); - exit; + chdir( $this->rsync_to ); } } diff --git a/src/mantle/testing/core-polyfill.php b/src/mantle/testing/core-polyfill.php index 2317a291c..031248c47 100644 --- a/src/mantle/testing/core-polyfill.php +++ b/src/mantle/testing/core-polyfill.php @@ -18,3 +18,27 @@ function rand_str( $len = 32 ): string { return substr( md5( uniqid( wp_rand() ) ), 0, $len ); } endif; + +if ( ! function_exists( 'ensure_trailingslash' ) ) : + /** + * Appends a trailing slash. + * + * @param string $string String to append a trailing slash to. + * @return string + */ + function ensure_trailingslash( $string ) { + return remove_trailingslash( $string ) . '/'; + } +endif; + +if ( ! function_exists( 'remove_trailingslash' ) ) : + /** + * Removes trailing forward slashes and backslashes if they exist. + * + * @param string $string What to remove the trailing slashes from. + * @return string String without the trailing slashes. + */ + function remove_trailingslash( $string ) { + return rtrim( $string, '/\\' ); + } +endif; diff --git a/src/mantle/testing/wordpress-bootstrap.php b/src/mantle/testing/wordpress-bootstrap.php index 3b0079b2c..a1906e51e 100644 --- a/src/mantle/testing/wordpress-bootstrap.php +++ b/src/mantle/testing/wordpress-bootstrap.php @@ -14,6 +14,9 @@ require_once __DIR__ . '/class-utils.php'; require_once __DIR__ . '/class-wp-die.php'; +// Ensure that Composer is loaded properly in the sub-process. +Utils::ensure_composer_loaded(); + /* * Globalize some WordPress variables, because PHPUnit loads this file inside a function. * See: https://github.com/sebastianbergmann/phpunit/issues/325 @@ -48,38 +51,30 @@ // Install WordPress if we're not in the sub-process that installs WordPress. if ( ! defined( 'WP_INSTALLING' ) || ! WP_INSTALLING ) { - echo 'WordPress installation not found, installing in temporary directory: ' . WP_TESTS_INSTALL_PATH . PHP_EOL; - - // Download the latest installation command from GitHub and install WordPress. - $cmd = sprintf( - 'WP_CORE_DIR=%s curl -s %s | bash -s %s %s %s %s %s %s', - WP_TESTS_INSTALL_PATH, - 'https://raw.githubusercontent.com/alleyinteractive/mantle-ci/HEAD/install-wp-tests.sh', - Utils::shell_safe( defined( 'DB_NAME' ) ? DB_NAME : Utils::env( 'WP_DB_NAME', 'wordpress_unit_tests' ) ), - Utils::shell_safe( defined( 'DB_USER' ) ? DB_USER : Utils::env( 'WP_DB_USER', 'root' ) ), - Utils::shell_safe( defined( 'DB_PASSWORD' ) ? DB_PASSWORD : Utils::env( 'WP_DB_PASSWORD', 'root' ) ), - Utils::shell_safe( defined( 'DB_HOST' ) ? DB_HOST : Utils::env( 'WP_DB_HOST', 'localhost' ) ), - Utils::shell_safe( Utils::env( 'WP_VERSION', 'latest' ) ), - Utils::shell_safe( Utils::env( 'WP_SKIP_DB_CREATE', 'false' ) ), + Utils::info( + 'WordPress installation not found, installing in temporary directory: ' . WP_TESTS_INSTALL_PATH . '' ); - $resp = system( $cmd, $retval ); - - if ( 0 !== $retval ) { - echo "\n🚨 Error downloading WordPress!\nResponse from installation command:\n\n$resp\n" . PHP_EOL; - exit( 1 ); - } + // Download the latest installation command from GitHub and install WordPress. + Utils::install_wordpress( WP_TESTS_INSTALL_PATH ); } } else { // The project is being loaded from inside a WordPress installation. - $config_file_path = preg_replace( '#/wp-content/.*$#', '/wp-tests-config.php', __DIR__ ); + if ( defined( 'WP_TESTS_INSTALL_PATH' ) ) { + $config_file_path = preg_replace( '#/wp-content/.*$#', '/wp-tests-config.php', WP_TESTS_INSTALL_PATH ); + } + + if ( empty( $config_file_path ) ) { + $config_file_path = preg_replace( '#/wp-content/.*$#', '/wp-tests-config.php', __DIR__ ); + } } if ( is_readable( $config_file_path ) ) { - echo "Using configuration file: [{$config_file_path}]\n"; + Utils::info( "Using configuration file: {$config_file_path}" ); + require_once $config_file_path; } elseif ( ! defined( 'WP_INSTALLING' ) || ! WP_INSTALLING ) { - echo "No wp-tests-config.php file found, using default configuration.\n"; + Utils::info( 'No wp-tests-config.php file found, using default configuration.' ); } Utils::setup_configuration(); @@ -117,22 +112,35 @@ $installing_wp = defined( 'WP_INSTALLING' ) && WP_INSTALLING; if ( ! $installing_wp && '1' !== getenv( 'WP_TESTS_SKIP_INSTALL' ) ) { - $resp = system( WP_PHP_BINARY . ' ' . escapeshellarg( __DIR__ . '/install-wordpress.php' ) . ' ' . $multisite, $retval ); + $resp = Utils::command( + [ + WP_PHP_BINARY, + escapeshellarg( __DIR__ . '/install-wordpress.php' ), + $multisite, + // Utils::get_autoloader_path() + ], + $retval, + ); // Verify the return code and that 'Done!' is included in the output. - if ( 0 !== $retval || empty( $resp ) || false === strpos( $resp, 'Done!' ) ) { - echo "🚨 Error installing WordPress!\nResponse from installation script:\n\n$resp\n"; + if ( 0 !== $retval || empty( $resp ) || false === strpos( implode( ' ', $resp ), 'Done!' ) ) { + Utils::error( + '🚨 Error installing WordPress! Response from installation script:' + ); + + Utils::code( $resp ); + exit( $retval ); } } if ( $multisite && ! $installing_wp ) { - echo 'Running as multisite...' . PHP_EOL; + Utils::info( 'Running as multisite...' ); defined( 'MULTISITE' ) or define( 'MULTISITE', true ); defined( 'SUBDOMAIN_INSTALL' ) or define( 'SUBDOMAIN_INSTALL', false ); $GLOBALS['base'] = '/'; } elseif ( ! $installing_wp ) { - echo "Running as single site...\nℹī¸ To run multisite, pass WP_MULTISITE=1 or set the WP_TESTS_MULTISITE=1 constant.\n"; + Utils::info( "Running as single site...\nℹī¸ To run multisite, pass WP_MULTISITE=1 or set the WP_TESTS_MULTISITE=1 constant." ); } unset( $multisite ); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index fa5a581c4..26c6361c1 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -13,5 +13,3 @@ \Mantle\Testing\manager() ->maybe_rsync_plugin() ->install(); - -// \Mantle\Testing\install(); From 55942237315d75e0d4b1501330ae7c4cfdaa4113 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Tue, 11 Oct 2022 17:21:15 -0400 Subject: [PATCH 04/15] Require in testing package --- composer.json | 2 +- src/mantle/testing/composer.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 82c3754b3..f54fe606c 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "monolog/monolog": "^2.7", "nesbot/carbon": "^2.53", "nette/php-generator": "^3.6", - "nunomaduro/termwind": "^1.14", "psr/container": "^1.1.1 || ^2.0.1", "psr/log": "^1.0.1 || ^2.0 || ^3.0", "symfony/finder": "^5.3", @@ -45,6 +44,7 @@ "mockery/mockery": "^1.3", "nunomaduro/collision": "^5.0", "phpunit/phpunit": "^9.3.3", + "nunomaduro/termwind": "^1.14", "symplify/monorepo-builder": "^10.1" }, "replace": { diff --git a/src/mantle/testing/composer.json b/src/mantle/testing/composer.json index 93df0342c..19cdee8cc 100644 --- a/src/mantle/testing/composer.json +++ b/src/mantle/testing/composer.json @@ -10,7 +10,8 @@ "mantle-framework/database": "^0.7", "mantle-framework/http-client": "^0.7", "mantle-framework/http": "^0.7", - "mantle-framework/support": "^0.7" + "mantle-framework/support": "^0.7", + "nunomaduro/termwind": "^1.14" }, "extra": { "branch-alias": { From f7f582459c73528ae304092b7253c278837bbeb7 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Tue, 11 Oct 2022 17:28:17 -0400 Subject: [PATCH 05/15] Dropping 7.4 support --- .github/workflows/tests.yml | 2 +- composer.json | 2 +- monorepo-builder.php | 2 +- src/mantle/assets/composer.json | 2 +- src/mantle/auth/composer.json | 2 +- src/mantle/cache/composer.json | 2 +- src/mantle/config/composer.json | 2 +- src/mantle/console/composer.json | 2 +- src/mantle/container/composer.json | 2 +- src/mantle/contracts/composer.json | 2 +- src/mantle/database/composer.json | 2 +- src/mantle/events/composer.json | 2 +- src/mantle/facade/composer.json | 2 +- src/mantle/faker/composer.json | 2 +- src/mantle/filesystem/composer.json | 2 +- src/mantle/http-client/composer.json | 2 +- src/mantle/http/composer.json | 2 +- src/mantle/log/composer.json | 2 +- src/mantle/query-monitor/composer.json | 2 +- src/mantle/queue/composer.json | 2 +- src/mantle/rest-api/composer.json | 2 +- src/mantle/scheduling/composer.json | 2 +- src/mantle/support/composer.json | 2 +- src/mantle/testing/composer.json | 2 +- src/mantle/testkit/composer.json | 2 +- src/mantle/view/composer.json | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 13b721c60..ad4056f02 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: php-tests: strategy: matrix: - php: [7.4, 8.0] + php: [8.0] wordpress: ["latest"] multisite: [true, false] uses: alleyinteractive/.github/.github/workflows/php-tests.yml@main diff --git a/composer.json b/composer.json index f54fe606c..b4746aac5 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "alleyinteractive/wp-asset-manager": "^1.0", "alleyinteractive/wp-caper": "^1.0", diff --git a/monorepo-builder.php b/monorepo-builder.php index e68efe2a0..87974fb9f 100644 --- a/monorepo-builder.php +++ b/monorepo-builder.php @@ -50,7 +50,7 @@ [ ComposerJsonSection::REQUIRE => [ 'alleyinteractive/composer-wordpress-autoloader' => '^1.0', - 'php' => '^7.4|^8.0', + 'php' => '^8.0', ], ComposerJsonSection::REQUIRE_DEV => [ 'alleyinteractive/alley-coding-standards' => '^0.3', diff --git a/src/mantle/assets/composer.json b/src/mantle/assets/composer.json index 08a8aeadd..acf283ca4 100644 --- a/src/mantle/assets/composer.json +++ b/src/mantle/assets/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Asset Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "alleyinteractive/wp-asset-manager": "^1.0", "mantle-framework/contracts": "^0.7", diff --git a/src/mantle/auth/composer.json b/src/mantle/auth/composer.json index 5502d43ff..6d6331e9f 100644 --- a/src/mantle/auth/composer.json +++ b/src/mantle/auth/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Auth Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/http": "^0.7", "symfony/http-kernel": "^5.3" diff --git a/src/mantle/cache/composer.json b/src/mantle/cache/composer.json index 5b05494d8..5a3bfaa90 100644 --- a/src/mantle/cache/composer.json +++ b/src/mantle/cache/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Cache Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "mantle-framework/support": "^0.7", diff --git a/src/mantle/config/composer.json b/src/mantle/config/composer.json index 86bb13596..d8862a0ee 100644 --- a/src/mantle/config/composer.json +++ b/src/mantle/config/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Config Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "mantle-framework/support": "^0.7" diff --git a/src/mantle/console/composer.json b/src/mantle/console/composer.json index 8c1ce8450..4299c6caa 100644 --- a/src/mantle/console/composer.json +++ b/src/mantle/console/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Console Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "mantle-framework/support": "^0.7", diff --git a/src/mantle/container/composer.json b/src/mantle/container/composer.json index 78afa7198..11341ece6 100644 --- a/src/mantle/container/composer.json +++ b/src/mantle/container/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Container Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "psr/container": "^1.1.1 || ^2.0.1" diff --git a/src/mantle/contracts/composer.json b/src/mantle/contracts/composer.json index 940f11005..52cc8df39 100644 --- a/src/mantle/contracts/composer.json +++ b/src/mantle/contracts/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Contracts Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "psr/container": "^1.1.1 || ^2.0.1" }, diff --git a/src/mantle/database/composer.json b/src/mantle/database/composer.json index 1bb862d6b..876029bb5 100644 --- a/src/mantle/database/composer.json +++ b/src/mantle/database/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Database Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "alleyinteractive/wp-filter-side-effects": "^1.0", "mantle-framework/contracts": "^0.7", diff --git a/src/mantle/events/composer.json b/src/mantle/events/composer.json index cddf67b89..26372eaf3 100644 --- a/src/mantle/events/composer.json +++ b/src/mantle/events/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Events Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/container": "^0.7", "mantle-framework/contracts": "^0.7", diff --git a/src/mantle/facade/composer.json b/src/mantle/facade/composer.json index 487954218..983af9f61 100644 --- a/src/mantle/facade/composer.json +++ b/src/mantle/facade/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Facade Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7" }, diff --git a/src/mantle/faker/composer.json b/src/mantle/faker/composer.json index 9012112b2..d1532db5f 100644 --- a/src/mantle/faker/composer.json +++ b/src/mantle/faker/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Faker Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "fakerphp/faker": "^1.16" }, diff --git a/src/mantle/filesystem/composer.json b/src/mantle/filesystem/composer.json index 590e97fbc..1a3bdd7ee 100644 --- a/src/mantle/filesystem/composer.json +++ b/src/mantle/filesystem/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Filesystem Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "league/flysystem": "^1.1", "league/flysystem-cached-adapter": "^1.1", diff --git a/src/mantle/http-client/composer.json b/src/mantle/http-client/composer.json index 599c7ee44..0e3d23640 100644 --- a/src/mantle/http-client/composer.json +++ b/src/mantle/http-client/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Http Client Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/wp-concurrent-remote-requests": "^1.0.0", "mantle-framework/support": "^0.7" }, diff --git a/src/mantle/http/composer.json b/src/mantle/http/composer.json index 4c4bc3385..5934a1d84 100644 --- a/src/mantle/http/composer.json +++ b/src/mantle/http/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Http Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "illuminate/view": "^8.6", "mantle-framework/contracts": "^0.7", "mantle-framework/filesystem": "^0.7", diff --git a/src/mantle/log/composer.json b/src/mantle/log/composer.json index 08276dec6..bebbc64c5 100644 --- a/src/mantle/log/composer.json +++ b/src/mantle/log/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Log Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "mantle-framework/support": "^0.7", diff --git a/src/mantle/query-monitor/composer.json b/src/mantle/query-monitor/composer.json index d831d28a9..a858c517a 100644 --- a/src/mantle/query-monitor/composer.json +++ b/src/mantle/query-monitor/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Query Monitor Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "mantle-framework/database": "^0.7", diff --git a/src/mantle/queue/composer.json b/src/mantle/queue/composer.json index 5fd9b2520..302ce69c0 100644 --- a/src/mantle/queue/composer.json +++ b/src/mantle/queue/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Queue Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "laravel/serializable-closure": "^1.2", "mantle-framework/console": "^0.7", diff --git a/src/mantle/rest-api/composer.json b/src/mantle/rest-api/composer.json index 4b1a64abd..e6842eec8 100644 --- a/src/mantle/rest-api/composer.json +++ b/src/mantle/rest-api/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework REST API Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7" }, diff --git a/src/mantle/scheduling/composer.json b/src/mantle/scheduling/composer.json index 96cd6ac3f..c74a681b1 100644 --- a/src/mantle/scheduling/composer.json +++ b/src/mantle/scheduling/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Scheduling Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "dragonmantank/cron-expression": "^3.1", "guzzlehttp/guzzle": "^6.3.1 || ^7.3", diff --git a/src/mantle/support/composer.json b/src/mantle/support/composer.json index 42652de9c..6ec5d30b1 100644 --- a/src/mantle/support/composer.json +++ b/src/mantle/support/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework Support Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "monolog/monolog": "^2.7", diff --git a/src/mantle/testing/composer.json b/src/mantle/testing/composer.json index 19cdee8cc..018e9a0a9 100644 --- a/src/mantle/testing/composer.json +++ b/src/mantle/testing/composer.json @@ -4,7 +4,7 @@ "keywords": ["testing", "mantle"], "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7", "mantle-framework/database": "^0.7", diff --git a/src/mantle/testkit/composer.json b/src/mantle/testkit/composer.json index 6c18c7a48..94f412d6c 100644 --- a/src/mantle/testkit/composer.json +++ b/src/mantle/testkit/composer.json @@ -4,7 +4,7 @@ "keywords": ["testing", "mantle"], "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/config": "^0.7", "mantle-framework/container": "^0.7", diff --git a/src/mantle/view/composer.json b/src/mantle/view/composer.json index 319242db8..06047ede7 100644 --- a/src/mantle/view/composer.json +++ b/src/mantle/view/composer.json @@ -3,7 +3,7 @@ "description": "The Mantle Framework View Package", "type": "project", "require": { - "php": "^7.4|^8.0", + "php": "^8.0", "alleyinteractive/composer-wordpress-autoloader": "^1.0", "mantle-framework/contracts": "^0.7" }, From d2121b983646d748acd1894510f4b11e39d1224d Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Tue, 11 Oct 2022 17:37:27 -0400 Subject: [PATCH 06/15] Remove ds store --- tests/.DS_Store | Bin 10244 -> 0 bytes tests/includes/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/.DS_Store delete mode 100644 tests/includes/.DS_Store diff --git a/tests/.DS_Store b/tests/.DS_Store deleted file mode 100644 index 4e45eb3857e6cc4653c82359dc84524735eee257..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeI1O>7%Q6vyA@!`_XdG7?BlRl!Oe3Q~|9idt@UL)rr$BC0DQK}l@Ko7k$o>#o;v zQ54BVh*O1%#3^v#K#0VJE5`^b=%oT7fjDqM9Jp}pu~Ofg-HhMthn))&m1d*e+3ft^ zd%t}%J3F%m0As1&SOl;Ez{H)(;uCmC*{GiO#5NUOc^69q?EwPlwYL^48(ycIQ0ogi z13Cjb13Cjb13Cl$hYa95n>Mo$minkOpfjK|ATvPYgN-|t<)|Enr5HN!AeI1F&fsOS z;W@4YgpD1Q<)|Enr7%UG;p)MNOpR!XVT9&bZ<8F$a#Rk(GBgJxGzTM!Y(y&*LqtbA zTgbsEhowI14Co9bGeB$i9MqtPe@=4!e(FNJzT+(~*V|qlubcPQU;pW_clTma)0n8~ zHu-mg61sp{*g%pEXo91DMX>hOTF&4$Bm=YWcq4*zg&JRs8aa&ZfeV|^f-RLG_oKK+ zR?itOZ%GEl2dBu=q;TXTjvmsq-9me8;ybw>fLs$7nDkW7*o?Tv$?!!%@wS|iGuZhrRfbSK`rR_ zmTLZb@pPrtaOyRGwbclkR~`3K+u3&9xBWM3f#bhN;;Ww5MnQO9tH0B72J6MAU-R6c z)^Z(R_zQhpTWz@wZ?NR`-9}I7Bj@6Lr4}^NkNJGL_6ywsSf;gJJh`*8SSl^pFQ0pL zcfsB{e;&_YIeTt**D}rdGncQd^*{V%@AI$rzdrc>2Vn(9G~0rw!vE#*F8NHRMQyP9 zwR9D4vQHn#CQI?h8*RK&X||9$#ou~6@%eaxQU%VfUcUy#v!lc4ELXTf87b zia|@IIJ=jv3=}8V(lng${wc|r@WtuI=~ON; z&`u+f7oR%JeS5o=>@f)FU?KbXJ+-W1-Ff4@$ z9!Nsh#pihZhrUw15M2{5G~fN>jeu5tnQiGS?-&NgXO zfC^9nDnJFOz*iN>^4iS5dMXd20#x816tM3@fg9GuA<#b^7`z1l&JcFP+i0p z4uOckG^oI!YPJ{}bi_;M)x;q%=%U$tXx^;Zp{U=E^NXj8)i-u0 zq5pp+aYY5Fz+Wk#v(0X^#*?zPjvi;Vw!rsr%elkNFn0c7UV2jG6`Nzf VCJup4N8IT^{tTEdG%E0G1s*&b6^H-; From 2fc890e2af0a1e0b568a1dfce206f8c00a52d83d Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 16:33:06 -0400 Subject: [PATCH 07/15] Info message formatting fix --- src/mantle/testing/wordpress-bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mantle/testing/wordpress-bootstrap.php b/src/mantle/testing/wordpress-bootstrap.php index a1906e51e..7493a5241 100644 --- a/src/mantle/testing/wordpress-bootstrap.php +++ b/src/mantle/testing/wordpress-bootstrap.php @@ -140,7 +140,7 @@ defined( 'SUBDOMAIN_INSTALL' ) or define( 'SUBDOMAIN_INSTALL', false ); $GLOBALS['base'] = '/'; } elseif ( ! $installing_wp ) { - Utils::info( "Running as single site...\nℹī¸ To run multisite, pass WP_MULTISITE=1 or set the WP_TESTS_MULTISITE=1 constant." ); + Utils::info( "Running as single site...\n
ℹī¸ To run multisite, pass WP_MULTISITE=1 or set the WP_TESTS_MULTISITE=1 constant." ); } unset( $multisite ); From 42a7fc02319a72fa7da336b41a72182fc8f1180f Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 16:50:46 -0400 Subject: [PATCH 08/15] Wrap up rsyncing and proxy to new command --- .../testing/class-installation-manager.php | 3 +- .../concerns/trait-rsync-installation.php | 33 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/mantle/testing/class-installation-manager.php b/src/mantle/testing/class-installation-manager.php index 69edc305e..57ded8d7a 100644 --- a/src/mantle/testing/class-installation-manager.php +++ b/src/mantle/testing/class-installation-manager.php @@ -101,7 +101,8 @@ public function install() { require_once __DIR__ . '/core-polyfill.php'; if ( $this->rsync_to ) { - $this->rsync_before_install(); + $this->rsync_testsuite(); + return; } foreach ( $this->before_install_callbacks as $callback ) { diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php index dedc0bf47..5b2be2d88 100644 --- a/src/mantle/testing/concerns/trait-rsync-installation.php +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -20,6 +20,8 @@ * plugin/theme from code that is written in a standalone repository. For * example, a repository can contain only a theme. Mantle will internally rsync * the theme to a WordPress installation without needing to run a bash script. + * + * After the rsync is complete, PHPUnit will be rerun from the new location. */ trait Rsync_Installation { /** @@ -126,7 +128,7 @@ protected function is_within_wordpress_install(): bool { * This allows the plugin/theme project to properly situate itself within a * WordPress installation without needing to rsync it manually. */ - protected function rsync_before_install() { + protected function rsync_testsuite() { require_once __DIR__ . '/../class-utils.php'; $base_install_path = $this->get_installation_path(); @@ -210,5 +212,34 @@ protected function rsync_before_install() { ); chdir( $this->rsync_to ); + + $command = $this->get_phpunit_command(); + + // Proxy to the phpunit instance within the new rsynced WordPress installation. + Utils::info( + "Running {$command} in {$this->rsync_to}:", + 'Install Rsync' + ); + + system( $command, $result_code ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_system + + exit( (int) $result_code ); + } + + /** + * Generate the command that will be run inside the rsync-ed WordPress + * installation to fire off PHPUnit. + * + * @return string + */ + protected function get_phpunit_command(): string { + $args = (array) $_SERVER['argv'] ?? []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + + // Remove the first argument, which is the path to the phpunit binary. + array_shift( $args ); + + $executable = getenv( 'WP_PHPUNIT_PATH' ) ?: 'vendor/bin/phpunit'; + + return $executable . ' ' . implode( ' ', array_map( 'escapeshellarg', $args ) ); } } From b1cd522b906dd32a454af9147399a0213f1b6bb7 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 16:53:02 -0400 Subject: [PATCH 09/15] Fixing use --- src/mantle/testing/class-installation-manager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mantle/testing/class-installation-manager.php b/src/mantle/testing/class-installation-manager.php index 57ded8d7a..04da8ec3f 100644 --- a/src/mantle/testing/class-installation-manager.php +++ b/src/mantle/testing/class-installation-manager.php @@ -13,8 +13,8 @@ * Installation Manager */ class Installation_Manager { - use Concerns\Rsync_Installation, - Singleton; + use Concerns\Rsync_Installation; + use Singleton; /** * Callbacks for before installation. From 0705e8b8e60aa521a509e60e245c994745bde1c0 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 16:54:49 -0400 Subject: [PATCH 10/15] Remove older code that was previously required --- .../testing/class-installation-manager.php | 33 ++----------------- src/mantle/testing/class-utils.php | 5 --- .../concerns/trait-rsync-installation.php | 2 +- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/mantle/testing/class-installation-manager.php b/src/mantle/testing/class-installation-manager.php index 04da8ec3f..ae10c56bc 100644 --- a/src/mantle/testing/class-installation-manager.php +++ b/src/mantle/testing/class-installation-manager.php @@ -101,7 +101,7 @@ public function install() { require_once __DIR__ . '/core-polyfill.php'; if ( $this->rsync_to ) { - $this->rsync_testsuite(); + $this->perform_rsync_testsuite(); return; } @@ -110,7 +110,7 @@ public function install() { } try { - require_once $this->bootstrap_file_path(); + require_once __DIR__ . '/wordpress-bootstrap.php'; } catch ( \Throwable $throwable ) { Utils::error( '🚨 Failed to load the WordPress installation. Exception thrown:' ); Utils::code( $throwable->getMessage() ); @@ -123,33 +123,4 @@ public function install() { return $this; } - - /** - * Retrieve the bootstrap file path. - * - * @return string - */ - protected function bootstrap_file_path(): string { - if ( defined( 'WP_TESTS_BOOTSTRAP_FILE' ) ) { - return WP_TESTS_BOOTSTRAP_FILE; - } - - if ( ! $this->rsync_to ) { - return __DIR__ . '/wordpress-bootstrap.php'; - } - - $base_path = [ - $this->rsync_to . '/src/mantle/testing/wordpress-bootstrap.php', - $this->rsync_to . '/vendor/alleyinteractive/mantle-framework/src/mantle/testing/wordpress-bootstrap.php', - $this->rsync_to . '/vendor/mantle-framework/testing/src/mantle/testing/wordpress-bootstrap.php', - ]; - - foreach ( $base_path as $path ) { - if ( file_exists( $path ) ) { - return $path; - } - } - - return __DIR__ . '/wordpress-bootstrap.php'; - } } diff --git a/src/mantle/testing/class-utils.php b/src/mantle/testing/class-utils.php index 9ff61efa5..d0f6e2d38 100644 --- a/src/mantle/testing/class-utils.php +++ b/src/mantle/testing/class-utils.php @@ -8,13 +8,8 @@ namespace Mantle\Testing; use Mantle\Testing\Doubles\Spy_REST_Server; - use function Termwind\render; -if ( class_exists( Utils::class ) ) { - return; -} - require_once __DIR__ . '/concerns/trait-output-messages.php'; /** diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php index 5b2be2d88..5a7a57d65 100644 --- a/src/mantle/testing/concerns/trait-rsync-installation.php +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -128,7 +128,7 @@ protected function is_within_wordpress_install(): bool { * This allows the plugin/theme project to properly situate itself within a * WordPress installation without needing to rsync it manually. */ - protected function rsync_testsuite() { + protected function perform_rsync_testsuite() { require_once __DIR__ . '/../class-utils.php'; $base_install_path = $this->get_installation_path(); From bd1b2e7ff689dd987ef78aa5893283224553ea54 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 17:02:58 -0400 Subject: [PATCH 11/15] Adding some debug messaging --- src/mantle/testing/class-utils.php | 46 ++++++++++++++++------ src/mantle/testing/wordpress-bootstrap.php | 2 + 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/mantle/testing/class-utils.php b/src/mantle/testing/class-utils.php index d0f6e2d38..9d4359881 100644 --- a/src/mantle/testing/class-utils.php +++ b/src/mantle/testing/class-utils.php @@ -291,6 +291,24 @@ public static function install_wordpress( string $directory ): void { } } + /** + * Check if the command is being run in debug mode. + * + * @return bool + */ + public static function is_debug_mode(): bool { + return ! empty( + array_intersect( + (array) $_SERVER['argv'] ?? [], // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + [ + '--debug', + '--verbose', + '-v', + ], + ) + ); + } + /** * Run a system command and return the output. * @@ -299,19 +317,12 @@ public static function install_wordpress( string $directory ): void { * @return string[] */ public static function command( $command, &$exit_code = null ) { + $is_debug_mode = static::is_debug_mode(); + // Display the command if in debug mode. - if ( - ! empty( - array_intersect( - (array) $_SERVER['argv'] ?? [], // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - [ - '--debug', - '--verbose', - '-v', - ], - ) - ) - ) { + if ( $is_debug_mode ) { + $time = microtime( true ); + render( '
Running: @@ -326,6 +337,17 @@ public static function command( $command, &$exit_code = null ) { exec( $command, $output, $exit_code ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec + // Display the command runtime if in debug mode. + if ( $is_debug_mode ) { + $time = microtime( true ) - $time; + + render( + '
+ Finished in ' . number_format( $time, 2 ) . 's with exit code ' . $exit_code . '. +
' + ); + } + return $output; } diff --git a/src/mantle/testing/wordpress-bootstrap.php b/src/mantle/testing/wordpress-bootstrap.php index 7493a5241..de8f85ded 100644 --- a/src/mantle/testing/wordpress-bootstrap.php +++ b/src/mantle/testing/wordpress-bootstrap.php @@ -131,6 +131,8 @@ Utils::code( $resp ); exit( $retval ); + } elseif ( Utils::is_debug_mode() ) { + Utils::info( 'WordPress installation complete.' ); } } From f6f57b3daf9d2e4f6de4925242e85e1abc4546f6 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 17:07:50 -0400 Subject: [PATCH 12/15] Clarify default and doc --- src/mantle/testing/concerns/trait-rsync-installation.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php index 5a7a57d65..8e67e3693 100644 --- a/src/mantle/testing/concerns/trait-rsync-installation.php +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -41,14 +41,15 @@ trait Rsync_Installation { /** * Rsync the code base to be located under a valid WordPress installation. * - * By default, the codebase will be rsynced to the `wp-content` directory. + * By default, the codebase will be rsynced to the `wp-content` directory. The + * `to` path is assumed to be relative to the `wp-content` folder. * * @param string $to Location to rsync to within `wp-content`. * @param string $from Location to rsync from. * @return static */ public function rsync( string $to = null, string $from = null ) { - $this->rsync_to = $to ?: $this->get_installation_path() . '/wp-content/plugins/plugin'; + $this->rsync_to = $to ?: '/'; $this->rsync_from = $from ?: getcwd() . '/'; return $this; From d017e6c037c20c40f204a864aaa85428a7adeef4 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 20:11:53 -0400 Subject: [PATCH 13/15] Testing Github actions From cbf546641c6a0ed9d24f374f9c44db68f6608953 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Mon, 24 Oct 2022 21:51:52 -0400 Subject: [PATCH 14/15] Include a colon with the prefix for asci --- src/mantle/testing/concerns/trait-output-messages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mantle/testing/concerns/trait-output-messages.php b/src/mantle/testing/concerns/trait-output-messages.php index 3b9893a55..9e4782af4 100644 --- a/src/mantle/testing/concerns/trait-output-messages.php +++ b/src/mantle/testing/concerns/trait-output-messages.php @@ -33,7 +33,7 @@ protected static function message( render( sprintf( '
-
%s
+
%s:
%s
', $parent_classes, From 977af0a3802d23c72f9cb12c37a413317a4cc214 Mon Sep 17 00:00:00 2001 From: Sean Fisher Date: Tue, 25 Oct 2022 18:03:48 -0400 Subject: [PATCH 15/15] Code review feedback --- src/mantle/testing/concerns/trait-rsync-installation.php | 2 +- src/mantle/testing/wordpress-bootstrap.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mantle/testing/concerns/trait-rsync-installation.php b/src/mantle/testing/concerns/trait-rsync-installation.php index 8e67e3693..b4c5b996f 100644 --- a/src/mantle/testing/concerns/trait-rsync-installation.php +++ b/src/mantle/testing/concerns/trait-rsync-installation.php @@ -202,7 +202,7 @@ protected function perform_rsync_testsuite() { ); if ( 0 !== $retval ) { - Utils::error( '🚨 Error installing rsyncing! Output from command:', 'Install Rsync' ); + Utils::error( '🚨 Error rsyncing! Output from command:', 'Install Rsync' ); Utils::code( $output ); exit( 1 ); } diff --git a/src/mantle/testing/wordpress-bootstrap.php b/src/mantle/testing/wordpress-bootstrap.php index de8f85ded..f2104d968 100644 --- a/src/mantle/testing/wordpress-bootstrap.php +++ b/src/mantle/testing/wordpress-bootstrap.php @@ -117,7 +117,6 @@ WP_PHP_BINARY, escapeshellarg( __DIR__ . '/install-wordpress.php' ), $multisite, - // Utils::get_autoloader_path() ], $retval, );