From f5973eeb35490335712f310e49f35a5917a50da6 Mon Sep 17 00:00:00 2001 From: gitlost Date: Fri, 17 Nov 2017 18:37:04 +0000 Subject: [PATCH 1/6] Update scaffolded tests to latest (enable error reporting). --- .travis.yml | 2 + bin/install-package-tests.sh | 1 + features/bootstrap/FeatureContext.php | 30 ++--- features/bootstrap/Process.php | 16 +++ features/bootstrap/support.php | 6 + features/bootstrap/utils.php | 182 ++++++++++++++++++++------ features/steps/then.php | 27 +++- features/steps/when.php | 2 +- utils/behat-tags.php | 6 +- 9 files changed, 207 insertions(+), 65 deletions(-) diff --git a/.travis.yml b/.travis.yml index 923370a29..b65648735 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,8 @@ env: matrix: include: + - php: 7.2 + env: WP_VERSION=nightly - php: 7.1 env: WP_VERSION=latest - php: 7.0 diff --git a/bin/install-package-tests.sh b/bin/install-package-tests.sh index 2ff49dd8d..d672d9a50 100755 --- a/bin/install-package-tests.sh +++ b/bin/install-package-tests.sh @@ -5,6 +5,7 @@ set -ex install_db() { mysql -e 'CREATE DATABASE IF NOT EXISTS wp_cli_test;' -uroot mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot + mysql -e 'GRANT ALL PRIVILEGES ON wp_cli_test_scaffold.* TO "wp_cli_test"@"localhost" IDENTIFIED BY "password1"' -uroot } install_db diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index aaf39713b..453c604ee 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -131,6 +131,12 @@ private static function get_process_env_variables() { if ( $php_args = getenv( 'WP_CLI_PHP_ARGS' ) ) { $env['WP_CLI_PHP_ARGS'] = $php_args; } + if ( $php_used = getenv( 'WP_CLI_PHP_USED' ) ) { + $env['WP_CLI_PHP_USED'] = $php_used; + } + if ( $php = getenv( 'WP_CLI_PHP' ) ) { + $env['WP_CLI_PHP'] = $php; + } if ( $travis_build_dir = getenv( 'TRAVIS_BUILD_DIR' ) ) { $env['TRAVIS_BUILD_DIR'] = $travis_build_dir; } @@ -526,7 +532,8 @@ public function background_proc( $cmd ) { $status = proc_get_status( $proc ); if ( !$status['running'] ) { - throw new RuntimeException( stream_get_contents( $pipes[2] ) ); + $stderr = is_resource( $pipes[2] ) ? ( ': ' . stream_get_contents( $pipes[2] ) ) : ''; + throw new RuntimeException( sprintf( "Failed to start background process '%s'%s.", $cmd, $stderr ) ); } else { $this->running_procs[] = $proc; } @@ -617,7 +624,8 @@ public function install_wp( $subdir = '' ) { 'title' => 'WP CLI Site', 'admin_user' => 'admin', 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' + 'admin_password' => 'password1', + 'skip-email' => true, ); $install_cache_path = ''; @@ -658,7 +666,8 @@ public function install_wp_with_composer( $vendor_directory = 'vendor' ) { 'title' => 'WP CLI Site with both WordPress and wp-cli as Composer dependencies', 'admin_user' => 'admin', 'admin_email' => 'admin@example.com', - 'admin_password' => 'password1' + 'admin_password' => 'password1', + 'skip-email' => true, ); $this->proc( 'wp core install', $install_args )->run_check(); @@ -686,26 +695,13 @@ public function composer_require_current_wp_cli() { $this->composer_command( 'require wp-cli/wp-cli:dev-master --optimize-autoloader --no-interaction' ); } - public function get_php_binary() { - if ( getenv( 'WP_CLI_PHP_USED' ) ) - return getenv( 'WP_CLI_PHP_USED' ); - - if ( getenv( 'WP_CLI_PHP' ) ) - return getenv( 'WP_CLI_PHP' ); - - if ( defined( 'PHP_BINARY' ) ) - return PHP_BINARY; - - return 'php'; - } - public function start_php_server( $subdir = '' ) { $dir = $this->variables['RUN_DIR'] . '/'; if ( $subdir ) { $dir .= trim( $subdir, '/' ) . '/'; } $cmd = Utils\esc_cmd( '%s -S %s -t %s -c %s %s', - $this->get_php_binary(), + Utils\get_php_binary(), 'localhost:8080', $dir, get_cfg_var( 'cfg_file_path' ), diff --git a/features/bootstrap/Process.php b/features/bootstrap/Process.php index 5016580b7..70c3c9f82 100644 --- a/features/bootstrap/Process.php +++ b/features/bootstrap/Process.php @@ -115,4 +115,20 @@ public function run_check() { return $r; } + + /** + * Run the command, but throw an Exception on error. + * Same as `run_check()` above, but checks the correct stderr. + * + * @return ProcessRun + */ + public function run_check_stderr() { + $r = $this->run(); + + if ( $r->return_code || ! empty( $r->stderr ) ) { + throw new \RuntimeException( $r ); + } + + return $r; + } } diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index a37a064f6..6aa17c6c3 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -2,6 +2,12 @@ // Utility functions used by Behat steps +function assertRegExp( $regex, $actual ) { + if ( ! preg_match( $regex, $actual ) ) { + throw new Exception( "Actual value: " . var_export( $actual, true ) ); + } +} + function assertEquals( $expected, $actual ) { if ( $expected != $actual ) { throw new Exception( "Actual value: " . var_export( $actual, true ) ); diff --git a/features/bootstrap/utils.php b/features/bootstrap/utils.php index 32caac15f..bb6e9ad11 100644 --- a/features/bootstrap/utils.php +++ b/features/bootstrap/utils.php @@ -30,7 +30,9 @@ function extract_from_phar( $path ) { register_shutdown_function( function() use ( $tmp_path ) { - @unlink( $tmp_path ); + if ( file_exists( $tmp_path ) ) { + unlink( $tmp_path ); + } } ); @@ -58,7 +60,7 @@ function load_dependencies() { } if ( ! $has_autoload ) { - fputs( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); + fwrite( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); exit( 3 ); } } @@ -138,7 +140,7 @@ function find_file_upward( $files, $dir = null, $stop_check = null ) { if ( is_null( $dir ) ) { $dir = getcwd(); } - while ( @is_readable( $dir ) ) { + while ( is_readable( $dir ) ) { // Stop walking up when the supplied callable returns true being passed the $dir if ( is_callable( $stop_check ) && call_user_func( $stop_check, $dir ) ) { return null; @@ -166,7 +168,7 @@ function is_path_absolute( $path ) { return true; } - return $path[0] === '/'; + return '/' === $path[0]; } /** @@ -227,12 +229,12 @@ function locate_wp_config() { static $path; if ( null === $path ) { + $path = false; + if ( file_exists( ABSPATH . 'wp-config.php' ) ) { $path = ABSPATH . 'wp-config.php'; } elseif ( file_exists( ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '/../wp-settings.php' ) ) { $path = ABSPATH . '../wp-config.php'; - } else { - $path = false; } if ( $path ) { @@ -244,7 +246,9 @@ function locate_wp_config() { } function wp_version_compare( $since, $operator ) { - return version_compare( str_replace( array( '-src' ), '', $GLOBALS['wp_version'] ), $since, $operator ); + $wp_version = str_replace( '-src', '', $GLOBALS['wp_version'] ); + $since = str_replace( '-src', '', $since ); + return version_compare( $wp_version, $since, $operator ); } /** @@ -358,9 +362,9 @@ function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { do { $tmpfile = basename( $filename ); $tmpfile = preg_replace( '|\.[^.]*$|', '', $tmpfile ); - $tmpfile .= '-' . substr( md5( rand() ), 0, 6 ); + $tmpfile .= '-' . substr( md5( mt_rand() ), 0, 6 ); $tmpfile = $tmpdir . $tmpfile . '.tmp'; - $fp = @fopen( $tmpfile, 'x' ); + $fp = fopen( $tmpfile, 'xb' ); if ( ! $fp && is_writable( $tmpdir ) && file_exists( $tmpfile ) ) { $tmpfile = ''; continue; @@ -379,10 +383,10 @@ function launch_editor_for_input( $input, $filename = 'WP-CLI' ) { $editor = getenv( 'EDITOR' ); if ( ! $editor ) { + $editor = 'vi'; + if ( isset( $_SERVER['OS'] ) && false !== strpos( $_SERVER['OS'], 'indows' ) ) { $editor = 'notepad'; - } else { - $editor = 'vi'; } } @@ -416,9 +420,9 @@ function mysql_host_to_cli_args( $raw_host ) { list( $assoc_args['host'], $extra ) = $host_parts; $extra = trim( $extra ); if ( is_numeric( $extra ) ) { - $assoc_args['port'] = intval( $extra ); + $assoc_args['port'] = (int) $extra; $assoc_args['protocol'] = 'tcp'; - } elseif ( $extra !== '' ) { + } elseif ( '' !== $extra ) { $assoc_args['socket'] = $extra; } } else { @@ -436,7 +440,9 @@ function run_mysql_command( $cmd, $assoc_args, $descriptors = null ) { } if ( isset( $assoc_args['host'] ) ) { + //@codingStandardsIgnoreStart $assoc_args = array_merge( $assoc_args, mysql_host_to_cli_args( $assoc_args['host'] ) ); + //@codingStandardsIgnoreEnd } $pass = $assoc_args['pass']; @@ -581,6 +587,7 @@ function replace_path_consts( $source, $path ) { function http_request( $method, $url, $data = null, $headers = array(), $options = array() ) { $cert_path = '/rmccue/requests/library/Requests/Transport/cacert.pem'; + $halt_on_error = ! isset( $options['halt_on_error'] ) || (bool) $options['halt_on_error']; if ( inside_phar() ) { // cURL can't read Phar archives $options['verify'] = extract_from_phar( @@ -594,17 +601,24 @@ function http_request( $method, $url, $data = null, $headers = array(), $options } } if ( empty( $options['verify'] ) ) { - WP_CLI::error( 'Cannot find SSL certificate.' ); + $error_msg = 'Cannot find SSL certificate.'; + if ( $halt_on_error ) { + WP_CLI::error( $error_msg ); + } + throw new \RuntimeException( $error_msg ); } } try { - $request = \Requests::request( $url, $headers, $data, $method, $options ); - return $request; + return \Requests::request( $url, $headers, $data, $method, $options ); } catch ( \Requests_Exception $ex ) { // CURLE_SSL_CACERT_BADFILE only defined for PHP >= 7. if ( 'curlerror' !== $ex->getType() || ! in_array( curl_errno( $ex->getData() ), array( CURLE_SSL_CONNECT_ERROR, CURLE_SSL_CERTPROBLEM, 77 /*CURLE_SSL_CACERT_BADFILE*/ ), true ) ) { - \WP_CLI::error( sprintf( "Failed to get url '%s': %s.", $url, $ex->getMessage() ) ); + $error_msg = sprintf( "Failed to get url '%s': %s.", $url, $ex->getMessage() ); + if ( $halt_on_error ) { + WP_CLI::error( $error_msg ); + } + throw new \RuntimeException( $error_msg, null, $ex ); } // Handle SSL certificate issues gracefully \WP_CLI::warning( sprintf( "Re-trying without verify after failing to get verified url '%s' %s.", $url, $ex->getMessage() ) ); @@ -612,7 +626,11 @@ function http_request( $method, $url, $data = null, $headers = array(), $options try { return \Requests::request( $url, $headers, $data, $method, $options ); } catch ( \Requests_Exception $ex ) { - \WP_CLI::error( sprintf( "Failed to get non-verified url '%s' %s.", $url, $ex->getMessage() ) ); + $error_msg = sprintf( "Failed to get non-verified url '%s' %s.", $url, $ex->getMessage() ); + if ( $halt_on_error ) { + WP_CLI::error( $error_msg ); + } + throw new \RuntimeException( $error_msg, null, $ex ); } } } @@ -698,11 +716,13 @@ function get_named_sem_ver( $new_version, $original_version ) { if ( ! is_null( $minor ) && Semver::satisfies( $new_version, "{$major}.{$minor}.x" ) ) { return 'patch'; - } elseif ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { + } + + if ( Semver::satisfies( $new_version, "{$major}.x.x" ) ) { return 'minor'; - } else { - return 'major'; } + + return 'major'; } /** @@ -770,16 +790,16 @@ function get_temp_dir() { return $temp; } + $temp = '/tmp/'; + // `sys_get_temp_dir()` introduced PHP 5.2.1. if ( $try = sys_get_temp_dir() ) { $temp = trailingslashit( $try ); } elseif ( $try = ini_get( 'upload_tmp_dir' ) ) { $temp = trailingslashit( $try ); - } else { - $temp = '/tmp/'; } - if ( ! @is_writable( $temp ) ) { + if ( ! is_writable( $temp ) ) { \WP_CLI::warning( "Temp directory isn't writable: {$temp}" ); } @@ -813,6 +833,18 @@ function parse_ssh_url( $url, $component = -1 ) { $bits[ $key ] = $matches[ $i ]; } } + + // Find the hostname from `vagrant ssh-config` automatically. + if ( preg_match( '/^vagrant:?/', $url ) ) { + if ( 'vagrant' === $bits['host'] && empty( $bits['scheme'] ) ) { + $ssh_config = shell_exec( 'vagrant ssh-config 2>/dev/null' ); + if ( preg_match( '/Host\s(.+)/', $ssh_config, $matches ) ) { + $bits['scheme'] = 'vagrant'; + $bits['host'] = $matches[1]; + } + } + } + switch ( $component ) { case PHP_URL_SCHEME: return isset( $bits['scheme'] ) ? $bits['scheme'] : null; @@ -835,25 +867,28 @@ function parse_ssh_url( $url, $component = -1 ) { * @access public * @category Input * - * @param string $noun Resource being affected (e.g. plugin) - * @param string $verb Type of action happening to the noun (e.g. activate) - * @param integer $total Total number of resource being affected. - * @param integer $successes Number of successful operations. - * @param integer $failures Number of failures. + * @param string $noun Resource being affected (e.g. plugin) + * @param string $verb Type of action happening to the noun (e.g. activate) + * @param integer $total Total number of resource being affected. + * @param integer $successes Number of successful operations. + * @param integer $failures Number of failures. + * @param null|integer $skips Optional. Number of skipped operations. Default null (don't show skips). */ -function report_batch_operation_results( $noun, $verb, $total, $successes, $failures ) { +function report_batch_operation_results( $noun, $verb, $total, $successes, $failures, $skips = null ) { $plural_noun = $noun . 's'; $past_tense_verb = past_tense_verb( $verb ); $past_tense_verb_upper = ucfirst( $past_tense_verb ); if ( $failures ) { + $failed_skipped_message = null === $skips ? '' : " ({$failures} failed" . ( $skips ? ", {$skips} skipped" : '' ) . ')'; if ( $successes ) { - WP_CLI::error( "Only {$past_tense_verb} {$successes} of {$total} {$plural_noun}." ); + WP_CLI::error( "Only {$past_tense_verb} {$successes} of {$total} {$plural_noun}{$failed_skipped_message}." ); } else { - WP_CLI::error( "No {$plural_noun} {$past_tense_verb}." ); + WP_CLI::error( "No {$plural_noun} {$past_tense_verb}{$failed_skipped_message}." ); } } else { - if ( $successes ) { - WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}." ); + $skipped_message = $skips ? " ({$skips} skipped)" : ''; + if ( $successes || $skips ) { + WP_CLI::success( "{$past_tense_verb_upper} {$successes} of {$total} {$plural_noun}{$skipped_message}." ); } else { $message = $total > 1 ? ucfirst( $plural_noun ) : ucfirst( $noun ); WP_CLI::success( "{$message} already {$past_tense_verb}." ); @@ -876,7 +911,7 @@ function parse_str_to_argv( $arguments ) { $argv = array_map( function( $arg ) { foreach ( array( '"', "'" ) as $char ) { - if ( $char === substr( $arg, 0, 1 ) && $char === substr( $arg, -1 ) ) { + if ( substr( $arg, 0, 1 ) === $char && substr( $arg, -1 ) === $char ) { $arg = substr( $arg, 1, -1 ); break; } @@ -916,14 +951,15 @@ function basename( $path, $suffix = '' ) { * * @return bool */ +// @codingStandardsIgnoreLine function isPiped() { $shellPipe = getenv( 'SHELL_PIPE' ); - if ( $shellPipe !== false ) { + if ( false !== $shellPipe ) { return filter_var( $shellPipe, FILTER_VALIDATE_BOOLEAN ); - } else { - return (function_exists( 'posix_isatty' ) && ! posix_isatty( STDOUT )); } + + return (function_exists( 'posix_isatty' ) && ! posix_isatty( STDOUT )); } /** @@ -992,9 +1028,11 @@ function glob_brace( $pattern, $dummy_flags = null ) { } $current++; } else { - if ( ( '}' === $pattern[ $current ] && $depth-- === 0 ) || ( ',' === $pattern[ $current ] && 0 === $depth ) ) { + if ( ( '}' === $pattern[ $current ] && 0 === $depth-- ) || ( ',' === $pattern[ $current ] && 0 === $depth ) ) { break; - } elseif ( '{' === $pattern[ $current++ ] ) { + } + + if ( '{' === $pattern[ $current++ ] ) { $depth++; } } @@ -1038,7 +1076,7 @@ function glob_brace( $pattern, $dummy_flags = null ) { . substr( $pattern, $p, $next - $p ) . substr( $pattern, $rest + 1 ); - if ( ( $result = glob_brace( $subpattern ) ) ) { + if ( $result = glob_brace( $subpattern ) ) { $paths = array_merge( $paths, $result ); } @@ -1070,6 +1108,31 @@ function glob_brace( $pattern, $dummy_flags = null ) { * @return string */ function get_suggestion( $target, array $options, $threshold = 2 ) { + + $suggestion_map = array( + 'check' => 'check-update', + 'clear' => 'flush', + 'decrement' => 'decr', + 'del' => 'delete', + 'directory' => 'dir', + 'exec' => 'eval', + 'exec-file' => 'eval-file', + 'increment' => 'incr', + 'language' => 'locale', + 'lang' => 'locale', + 'new' => 'create', + 'number' => 'count', + 'remove' => 'delete', + 'regen' => 'regenerate', + 'rep' => 'replace', + 'repl' => 'replace', + 'v' => 'version', + ); + + if ( array_key_exists( $target, $suggestion_map ) ) { + return $suggestion_map[ $target ]; + } + if ( empty( $options ) ) { return ''; } @@ -1218,3 +1281,40 @@ function past_tense_verb( $verb ) { } return $verb . 'ed'; } + +/** + * Get the path to the PHP binary used when executing WP-CLI. + * + * Environment values permit specific binaries to be indicated. + * + * @access public + * @category System + * + * @return string + */ +function get_php_binary() { + if ( $wp_cli_php_used = getenv( 'WP_CLI_PHP_USED' ) ) { + return $wp_cli_php_used; + } + + if ( $wp_cli_php = getenv( 'WP_CLI_PHP' ) ) { + return $wp_cli_php; + } + + // Available since PHP 5.4. + if ( defined( 'PHP_BINARY' ) ) { + return PHP_BINARY; + } + + // @codingStandardsIgnoreLine + if ( @is_executable( PHP_BINDIR . '/php' ) ) { + return PHP_BINDIR . '/php'; + } + + // @codingStandardsIgnoreLine + if ( is_windows() && @is_executable( PHP_BINDIR . '/php.exe' ) ) { + return PHP_BINDIR . '/php.exe'; + } + + return 'php'; +} diff --git a/features/steps/then.php b/features/steps/then.php index aa1f3f67f..21589e737 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -3,9 +3,9 @@ use Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; -$steps->Then( '/^the return code should be (\d+)$/', - function ( $world, $return_code ) { - if ( $return_code != $world->result->return_code ) { +$steps->Then( '/^the return code should( not)? be (\d+)$/', + function ( $world, $not, $return_code ) { + if ( ( ! $not && $return_code != $world->result->return_code ) || ( $not && $return_code == $world->result->return_code ) ) { throw new RuntimeException( $world->result ); } } @@ -153,7 +153,7 @@ function ( $world, $stream, $operator, $goal_ver ) { throw new Exception( $world->result ); } } -); +); $steps->Then( '/^the (.+) (file|directory) should (exist|not exist|be:|contain:|not contain:)$/', function ( $world, $path, $type, $action, $expected = null ) { @@ -200,6 +200,25 @@ function ( $world, $path, $type, $action, $expected = null ) { } ); +$steps->Then( '/^the contents of the (.+) file should match (((\/.+\/)|(#.+#))([a-z]+)?)$/', + function ( $world, $path, $expected ) { + $path = $world->replace_variables( $path ); + // If it's a relative path, make it relative to the current test dir + if ( '/' !== $path[0] ) { + $path = $world->variables['RUN_DIR'] . "/$path"; + } + $contents = file_get_contents( $path ); + assertRegExp( $expected, $contents ); + } +); + +$steps->Then( '/^(STDOUT|STDERR) should match (((\/.+\/)|(#.+#))([a-z]+)?)$/', + function ( $world, $stream, $expected ) { + $stream = strtolower( $stream ); + assertRegExp( $expected, $world->result->$stream ); + } +); + $steps->Then( '/^an email should (be sent|not be sent)$/', function( $world, $expected ) { if ( 'be sent' === $expected ) { assertNotEquals( 0, $world->email_sends ); diff --git a/features/steps/when.php b/features/steps/when.php index afe3f7a0d..d23aa0e66 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -6,7 +6,7 @@ function invoke_proc( $proc, $mode ) { $map = array( - 'run' => 'run_check', + 'run' => 'run_check_stderr', 'try' => 'run' ); $method = $map[ $mode ]; diff --git a/utils/behat-tags.php b/utils/behat-tags.php index ee51fc91e..9c87fb656 100644 --- a/utils/behat-tags.php +++ b/utils/behat-tags.php @@ -44,8 +44,10 @@ function version_tags( $prefix, $current, $operator = '<' ) { version_tags( 'less-than-php', PHP_VERSION, '>' ) ); -# Skip Github API tests by default because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 -$skip_tags[] = '@github-api'; +# Skip Github API tests if `GITHUB_TOKEN` not available because of rate limiting. See https://github.com/wp-cli/wp-cli/issues/1612 +if ( ! getenv( 'GITHUB_TOKEN' ) ) { + $skip_tags[] = '@github-api'; +} # Skip tests known to be broken. $skip_tags[] = '@broken'; From e37fa1a3cedea628007b78b8c6807af036ecfbad Mon Sep 17 00:00:00 2001 From: gitlost Date: Fri, 17 Nov 2017 21:13:23 +0000 Subject: [PATCH 2/6] Fix test breakages run -> try; comment_post_ID non-null; @rmdir on empty. --- features/option.feature | 40 +++++++++++++++++++++++++++++++++++- features/site-create.feature | 4 +++- features/site.feature | 38 +++++++++++++++++++++++++--------- features/term.feature | 4 ++-- src/Comment_Command.php | 3 ++- src/Site_Command.php | 9 +++++--- 6 files changed, 80 insertions(+), 18 deletions(-) diff --git a/features/option.feature b/features/option.feature index 9e23051b2..7c3fd8858 100644 --- a/features/option.feature +++ b/features/option.feature @@ -48,7 +48,7 @@ Feature: Manage WordPress options When I run `wp option add auto_opt --autoload=no 'bar'` Then STDOUT should not be empty - When I run `wp option list --search='auto_opt' --autoload` + When I run `wp option list --search='auto_opt' --autoload=off` Then STDOUT should not be empty When I run `wp option list | grep -q "str_opt"` @@ -65,6 +65,7 @@ Feature: Manage WordPress options When I try `wp option get str_opt` Then the return code should be 1 + And STDERR should be empty # Integer values When I run `wp option update blog_public 1` @@ -216,3 +217,40 @@ Feature: Manage WordPress options """ Success: Value passed for 'home' option is unchanged. """ + + Scenario: Bad values for autoload + Given a WP install + When I run `wp option add str_opt 'bar'` + Then STDOUT should not be empty + + When I try `wp option list --search='auto_opt' --autoload` + Then STDOUT should not be empty + And STDERR should be: + """ + Warning: --autoload parameter needs a value + """ + And the return code should be 0 + + When I try `wp option list --search='auto_opt' --autoload=no` + Then STDOUT should be empty + And STDERR should be: + """ + Error: Value of '--autoload' should be on or off. + """ + And the return code should be 1 + + When I try `wp option add str_opt_foo 'bar' --autoload` + Then STDOUT should not be empty + And STDERR should be: + """ + Warning: --autoload parameter needs a value + """ + And the return code should be 0 + + When I try `wp option add str_opt_foo 'bar' --autoload=off` + Then STDOUT should be empty + And STDERR should contain: + """ + Error: Parameter errors: + """ + And the return code should be 1 diff --git a/features/site-create.feature b/features/site-create.feature index cce5bd508..c4cf546b5 100644 --- a/features/site-create.feature +++ b/features/site-create.feature @@ -22,11 +22,13 @@ Feature: Create a new site on a WP multisite Success: Generated 'wp-config.php' file. """ - When I run `wp core multisite-install --url=localhost/dev/ --title=Test --admin_user=admin --admin_email=admin@example.org` + # Old versions of WP can generate wpdb database errors if the WP tables don't exist, so STDERR may or may not be empty + When I try `wp core multisite-install --url=localhost/dev/ --title=Test --admin_user=admin --admin_email=admin@example.org` Then STDOUT should contain: """ Success: Network installed. Don't forget to set up rewrite rules """ + And the return code should be 0 When I run `wp site list --fields=blog_id,url` Then STDOUT should be a table containing rows: diff --git a/features/site.feature b/features/site.feature index 79473bd4f..61647de8e 100644 --- a/features/site.feature +++ b/features/site.feature @@ -8,6 +8,8 @@ Feature: Manage sites in a multisite installation """ Network with id 1000 does not exist. """ + And STDOUT should be empty + And the return code should be 1 Scenario: Create a subdomain site Given a WP multisite subdomain install @@ -61,6 +63,7 @@ Feature: Manage sites in a multisite installation """ Error: You cannot delete the root site. """ + And STDOUT should be empty And the return code should be 1 When I run `wp site delete {SITE_ID} --yes` @@ -151,7 +154,7 @@ Feature: Manage sites in a multisite installation | blog_id | archived | | {FIRST_SITE} | 1 | - When I run `wp site archive {FIRST_SITE} {SECOND_SITE}` + When I try `wp site archive {FIRST_SITE} {SECOND_SITE}` Then STDERR should be: """ Warning: Site {FIRST_SITE} already archived. @@ -160,6 +163,7 @@ Feature: Manage sites in a multisite installation """ Success: Site {SECOND_SITE} archived. """ + And the return code should be 0 When I run `wp site list --fields=blog_id,archived` Then STDOUT should be a table containing rows: @@ -172,7 +176,7 @@ Feature: Manage sites in a multisite installation Success: Site {FIRST_SITE} unarchived. """ - When I run `wp site list --fields=blog_id,archived` + When I try `wp site list --fields=blog_id,archived` Then STDOUT should be a table containing rows: | blog_id | archived | | {FIRST_SITE} | 0 | @@ -182,6 +186,8 @@ Feature: Manage sites in a multisite installation """ Warning: You are not allowed to change the main site. """ + And STDOUT should be empty + And the return code should be 0 Scenario: Activate/deactivate a site Given a WP multisite install @@ -201,7 +207,7 @@ Feature: Manage sites in a multisite installation | blog_id | deleted | | {FIRST_SITE} | 1 | - When I run `wp site deactivate {FIRST_SITE} {SECOND_SITE}` + When I try `wp site deactivate {FIRST_SITE} {SECOND_SITE}` Then STDERR should be: """ Warning: Site {FIRST_SITE} already deactivated. @@ -210,6 +216,7 @@ Feature: Manage sites in a multisite installation """ Success: Site {SECOND_SITE} deactivated. """ + And the return code should be 0 When I run `wp site list --fields=blog_id,deleted` Then STDOUT should be a table containing rows: @@ -227,11 +234,13 @@ Feature: Manage sites in a multisite installation | blog_id | deleted | | {FIRST_SITE} | 0 | - When I run `wp site deactivate 1` + When I try `wp site deactivate 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. """ + And STDOUT should be empty + And the return code should be 0 Scenario: Mark/remove a site from spam Given a WP multisite install @@ -251,7 +260,7 @@ Feature: Manage sites in a multisite installation | blog_id | spam | | {FIRST_SITE} | 1 | - When I run `wp site spam {FIRST_SITE} {SECOND_SITE}` + When I try `wp site spam {FIRST_SITE} {SECOND_SITE}` Then STDERR should be: """ Warning: Site {FIRST_SITE} already marked as spam. @@ -260,6 +269,7 @@ Feature: Manage sites in a multisite installation """ Success: Site {SECOND_SITE} marked as spam. """ + And the return code should be 0 When I run `wp site list --fields=blog_id,spam` Then STDOUT should be a table containing rows: @@ -277,11 +287,13 @@ Feature: Manage sites in a multisite installation | blog_id | spam | | {FIRST_SITE} | 0 | - When I run `wp site spam 1` + When I try `wp site spam 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. """ + And STDOUT should be empty + And the return code should be 0 Scenario: Mark/remove a site as mature Given a WP multisite install @@ -301,7 +313,7 @@ Feature: Manage sites in a multisite installation | blog_id | mature | | {FIRST_SITE} | 1 | - When I run `wp site mature {FIRST_SITE} {SECOND_SITE}` + When I try `wp site mature {FIRST_SITE} {SECOND_SITE}` Then STDERR should be: """ Warning: Site {FIRST_SITE} already marked as mature. @@ -310,6 +322,7 @@ Feature: Manage sites in a multisite installation """ Success: Site {SECOND_SITE} marked as mature. """ + And the return code should be 0 When I run `wp site list --fields=blog_id,mature` Then STDOUT should be a table containing rows: @@ -327,11 +340,13 @@ Feature: Manage sites in a multisite installation | blog_id | mature | | {FIRST_SITE} | 0 | - When I run `wp site unmature 1` + When I try `wp site unmature 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. """ + And STDOUT should be empty + And the return code should be 0 Scenario: Set/Unset a site as public Given a WP multisite install @@ -351,7 +366,7 @@ Feature: Manage sites in a multisite installation | blog_id | public | | {FIRST_SITE} | 0 | - When I run `wp site private {FIRST_SITE} {SECOND_SITE}` + When I try `wp site private {FIRST_SITE} {SECOND_SITE}` Then STDERR should be: """ Warning: Site {FIRST_SITE} already marked as private. @@ -360,6 +375,7 @@ Feature: Manage sites in a multisite installation """ Success: Site {SECOND_SITE} marked as private. """ + And the return code should be 0 When I run `wp site list --fields=blog_id,public` Then STDOUT should be a table containing rows: @@ -377,11 +393,13 @@ Feature: Manage sites in a multisite installation | blog_id | public | | {FIRST_SITE} | 1 | - When I run `wp site private 1` + When I try `wp site private 1` Then STDERR should be: """ Warning: You are not allowed to change the main site. """ + And STDOUT should be empty + And the return code should be 0 Scenario: Permit CLI operations against archived and suspended sites Given a WP multisite install diff --git a/features/term.feature b/features/term.feature index 356602df1..be048f9a5 100644 --- a/features/term.feature +++ b/features/term.feature @@ -78,7 +78,7 @@ Feature: Manage WordPress terms """ And the return code should be 0 - When I run the previous command again + When I try the previous command again Then STDOUT should be: """ Success: Term already deleted. @@ -89,7 +89,7 @@ Feature: Manage WordPress terms """ And the return code should be 0 - When I run `wp term delete post_tag {TERM_ID} {TERM_ID_TWO}` + When I try `wp term delete post_tag {TERM_ID} {TERM_ID_TWO}` Then STDOUT should be: """ Deleted post_tag {TERM_ID_TWO}. diff --git a/src/Comment_Command.php b/src/Comment_Command.php index 830c078df..76b0b8d2d 100644 --- a/src/Comment_Command.php +++ b/src/Comment_Command.php @@ -163,6 +163,7 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); } + $comment_post_ID = empty( $assoc_args['post_id'] ) ? 1 : $assoc_args['post_id']; $comment_count = wp_count_comments(); $total = (int )$comment_count->total_comments; $limit = $total + $assoc_args['count']; @@ -170,7 +171,7 @@ public function generate( $args, $assoc_args ) { for ( $i = $total; $i < $limit; $i++ ) { $comment_id = wp_insert_comment( array( 'comment_content' => "Comment {$i}", - 'comment_post_ID' => $assoc_args['post_id'], + 'comment_post_ID' => $comment_post_ID, ) ); if ( 'progress' === $format ) { $notify->tick(); diff --git a/src/Site_Command.php b/src/Site_Command.php index b202799ed..0c30adefe 100644 --- a/src/Site_Command.php +++ b/src/Site_Command.php @@ -195,10 +195,11 @@ public function _empty( $args, $assoc_args ) { ); $files_to_unlink = $directories_to_delete = array(); + $is_main_site = is_main_site(); foreach ( $files as $fileinfo ) { $realpath = $fileinfo->getRealPath(); // Don't clobber subsites when operating on the main site - if ( is_main_site() && false !== stripos( $realpath, '/sites/' ) ) { + if ( $is_main_site && false !== stripos( $realpath, '/sites/' ) ) { continue; } if ( $fileinfo->isDir() ) { @@ -211,9 +212,11 @@ public function _empty( $args, $assoc_args ) { unlink( $file ); } foreach( $directories_to_delete as $directory ) { - rmdir( $directory ); + // Directory could be main sites directory '/sites' which may be non-empty. + @rmdir( $directory ); // @codingStandardsIgnoreLine } - rmdir( $upload_dir['basedir'] ); + // May be non-empty if '/sites' still around. + @rmdir( $upload_dir['basedir'] ); // @codingStandardsIgnoreLine } WP_CLI::success( "The site at '" . site_url() . "' was emptied." ); From 3caa4017488595a918fc65c7b659d8595b9c1062 Mon Sep 17 00:00:00 2001 From: gitlost Date: Sat, 18 Nov 2017 00:29:53 +0000 Subject: [PATCH 3/6] Remove unused chained_command; set & warn _SERVER['SERVER_NAME']; return code checks. --- features/comment-meta.feature | 2 ++ features/comment.feature | 44 +++++++++++++++++++++++++++++--- features/menu-location.feature | 2 ++ features/menu.feature | 1 + features/network-meta.feature | 3 ++- features/post-meta.feature | 4 ++- features/post-term.feature | 2 ++ features/post-type.feature | 1 + features/post.feature | 3 ++- features/site-empty.feature | 1 + features/site-option.feature | 2 ++ features/site.feature | 2 +- features/taxonomy.feature | 1 + features/term-meta.feature | 1 + features/term-recount.feature | 5 ++-- features/term.feature | 3 +++ features/user-generate.feature | 12 ++++++++- features/user-import-csv.feature | 7 +++-- features/user-meta.feature | 1 + features/user.feature | 6 +++++ src/Comment_Command.php | 12 +++++++++ src/User_Command.php | 5 +--- 22 files changed, 103 insertions(+), 17 deletions(-) diff --git a/features/comment-meta.feature b/features/comment-meta.feature index 12f459211..b1fd8831b 100644 --- a/features/comment-meta.feature +++ b/features/comment-meta.feature @@ -17,6 +17,7 @@ Feature: Manage comment custom fields """ Error: Could not find the comment with ID 999999. """ + And the return code should be 1 When I run `wp comment-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty @@ -42,6 +43,7 @@ Feature: Manage comment custom fields Error: Parameter errors: unknown -- hi parameter """ + And the return code should be 1 When I run `wp comment meta add 1 foo '"-- hi"' --format=json` Then STDOUT should contain: diff --git a/features/comment.feature b/features/comment.feature index 484c6e791..5b32354af 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -46,6 +46,7 @@ Feature: Manage WordPress comments """ Error: Invalid comment ID. """ + And the return code should be 1 When I run `wp comment create --comment_post_ID=1` And I run `wp comment create --comment_post_ID=1` @@ -67,6 +68,7 @@ Feature: Manage WordPress comments """ Error: Invalid comment ID. """ + And the return code should be 1 Scenario: Get details about an existing comment When I run `wp comment get 1` @@ -154,7 +156,7 @@ Feature: Manage WordPress comments Given I run `wp comment create --comment_post_ID=1 --comment_approved=0 --porcelain` And save STDOUT as {COMMENT_ID} - When I run `wp comment approve {COMMENT_ID}` + When I run `wp comment approve {COMMENT_ID} --url=www.example.com` Then STDOUT should contain: """ Approved comment {COMMENT_ID} @@ -166,7 +168,7 @@ Feature: Manage WordPress comments 1 """ - When I run `wp comment unapprove {COMMENT_ID}` + When I run `wp comment unapprove {COMMENT_ID} --url=www.example.com` Then STDOUT should contain: """ Unapproved comment {COMMENT_ID} @@ -178,13 +180,47 @@ Feature: Manage WordPress comments 0 """ + When I try `wp comment approve {COMMENT_ID}` + Then STDOUT should contain: + """ + Approved comment {COMMENT_ID} + """ + And STDERR should contain: + """ + Warning: `$_SERVER['SERVER_NAME']` not set. Setting to 'example.com'. Notification email sent to post author may appear to come from 'example.com'. + """ + And the return code should be 0 + + When I run `wp comment get --field=comment_approved {COMMENT_ID}` + Then STDOUT should be: + """ + 1 + """ + + When I try `wp comment unapprove {COMMENT_ID}` + Then STDOUT should contain: + """ + Unapproved comment {COMMENT_ID} + """ + And STDERR should contain: + """ + Warning: `$_SERVER['SERVER_NAME']` not set. Setting to 'example.com'. Notification email sent to post author may appear to come from 'example.com'. + """ + And the return code should be 0 + + When I run `wp comment get --field=comment_approved {COMMENT_ID}` + Then STDOUT should be: + """ + 0 + """ + Scenario: Approving/unapproving comments with multidigit comment ID Given I run `wp comment delete $(wp comment list --field=ID)` And I run `wp comment generate --count=10 --quiet` And I run `wp comment create --porcelain` And save STDOUT as {COMMENT_ID} - When I run `wp comment unapprove {COMMENT_ID}` + When I run `wp comment unapprove {COMMENT_ID} --url=www.example.com` Then STDOUT should contain: """ Unapproved comment {COMMENT_ID} @@ -196,7 +232,7 @@ Feature: Manage WordPress comments 10 """ - When I run `wp comment approve {COMMENT_ID}` + When I run `wp comment approve {COMMENT_ID} --url=www.example.com` Then STDOUT should contain: """ Approved comment {COMMENT_ID} diff --git a/features/menu-location.feature b/features/menu-location.feature index 766fa6443..74c0155d9 100644 --- a/features/menu-location.feature +++ b/features/menu-location.feature @@ -35,6 +35,7 @@ Feature: Manage WordPress menu locations """ Error: Invalid menu secondary-menu. """ + And the return code should be 1 When I run `wp menu create "Secondary Menu"` And I try `wp menu location assign secondary-menu secondary` @@ -42,6 +43,7 @@ Feature: Manage WordPress menu locations """ Error: Invalid location secondary. """ + And the return code should be 1 When I run `wp menu location assign secondary-menu primary` Then STDOUT should be: diff --git a/features/menu.feature b/features/menu.feature index 95d179617..7059f9414 100644 --- a/features/menu.feature +++ b/features/menu.feature @@ -62,6 +62,7 @@ Feature: Manage WordPress menus Warning: Couldn't delete menu 'Your menu'. Error: No menus deleted. """ + And the return code should be 1 When I run `wp menu create "My Menu"` And I run `wp menu list --fields=name,slug` diff --git a/features/network-meta.feature b/features/network-meta.feature index f81c3b1b5..528a3416c 100644 --- a/features/network-meta.feature +++ b/features/network-meta.feature @@ -3,7 +3,7 @@ Feature: Manage network-wide custom fields. Scenario: Non-multisite Given a WP install - When I try `wp network-meta` + When I run `wp network-meta` Then STDOUT should contain: """ usage: wp network meta @@ -15,3 +15,4 @@ Feature: Manage network-wide custom fields. """ This is not a multisite install. """ + And the return code should be 1 diff --git a/features/post-meta.feature b/features/post-meta.feature index 11442858c..e738914c2 100644 --- a/features/post-meta.feature +++ b/features/post-meta.feature @@ -17,6 +17,7 @@ Feature: Manage post custom fields """ Error: Could not find the post with ID 999999. """ + And the return code should be 1 When I run `wp post-meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty @@ -116,6 +117,7 @@ Feature: Manage post custom fields """ Error: Please specify a meta key, or use the --all flag. """ + And the return code should be 1 When I run `wp post meta delete 1 --all` Then STDOUT should contain: @@ -443,4 +445,4 @@ Feature: Manage post custom fields Then STDOUT should be JSON containing: """ [ "new", "bar" ] - """ \ No newline at end of file + """ diff --git a/features/post-term.feature b/features/post-term.feature index cd80118ac..67993d256 100644 --- a/features/post-term.feature +++ b/features/post-term.feature @@ -37,6 +37,7 @@ Feature: Manage post term """ Error: Invalid taxonomy foo2. """ + And the return code should be 1 When I run `wp post term set 1 category new` Then STDOUT should be: @@ -214,3 +215,4 @@ Feature: Manage post term """ Error: No need to specify terms while removing all terms. """ + And the return code should be 1 diff --git a/features/post-type.feature b/features/post-type.feature index 08f2a1f61..0a73beef5 100644 --- a/features/post-type.feature +++ b/features/post-type.feature @@ -16,6 +16,7 @@ Feature: Manage WordPress post types """ Error: Post type invalid-post-type doesn't exist. """ + And the return code should be 1 When I run `wp post-type get page` Then STDOUT should be a table containing rows: diff --git a/features/post.feature b/features/post.feature index 48e57ce65..ab0bd1013 100644 --- a/features/post.feature +++ b/features/post.feature @@ -88,7 +88,7 @@ Feature: Manage WordPress posts """ And the return code should be 0 - When I try `EDITOR='ex -i NONE -c %s/content/bunkum -c wq' wp post edit {POST_ID}` + When I run `EDITOR='ex -i NONE -c %s/content/bunkum -c wq' wp post edit {POST_ID}` Then STDERR should be empty Then STDOUT should contain: """ @@ -155,6 +155,7 @@ Feature: Manage WordPress posts """ Error: Unable to read content from 'invalid-file.html'. """ + And the return code should be 1 Scenario: Creating/listing posts When I run `wp post create --post_title='Publish post' --post_content='Publish post content' --post_status='publish' --porcelain` diff --git a/features/site-empty.feature b/features/site-empty.feature index 2f5e49b80..bc30d40e4 100644 --- a/features/site-empty.feature +++ b/features/site-empty.feature @@ -15,6 +15,7 @@ Feature: Empty a WordPress site of its data """ Error: This is not a multisite install. """ + And the return code should be 1 When I run `wp post create --post_title='Test post' --post_content='Test content.' --porcelain` Then STDOUT should be: diff --git a/features/site-option.feature b/features/site-option.feature index fdd393217..98d4088df 100644 --- a/features/site-option.feature +++ b/features/site-option.feature @@ -118,12 +118,14 @@ Feature: Manage WordPress site options """ Error: This is not a multisite install. """ + And the return code should be 1 When I try `wp site option add str_opt 'bar'` Then STDERR should be: """ Error: This is not a multisite install. """ + And the return code should be 1 Scenario: Filter options by `--site_id` Given a WP multisite install diff --git a/features/site.feature b/features/site.feature index 61647de8e..e217f746c 100644 --- a/features/site.feature +++ b/features/site.feature @@ -176,7 +176,7 @@ Feature: Manage sites in a multisite installation Success: Site {FIRST_SITE} unarchived. """ - When I try `wp site list --fields=blog_id,archived` + When I run `wp site list --fields=blog_id,archived` Then STDOUT should be a table containing rows: | blog_id | archived | | {FIRST_SITE} | 0 | diff --git a/features/taxonomy.feature b/features/taxonomy.feature index b1f6646fb..d7af6de75 100644 --- a/features/taxonomy.feature +++ b/features/taxonomy.feature @@ -22,6 +22,7 @@ Feature: Manage WordPress taxonomies """ Error: Taxonomy invalid-taxonomy doesn't exist. """ + And the return code should be 1 When I run `wp taxonomy get category` Then STDOUT should be a table containing rows: diff --git a/features/term-meta.feature b/features/term-meta.feature index fcc7b6581..4389607c9 100644 --- a/features/term-meta.feature +++ b/features/term-meta.feature @@ -18,6 +18,7 @@ Feature: Manage term custom fields """ Error: Could not find the term with ID 999999. """ + And the return code should be 1 When I run `wp term meta set 1 foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty diff --git a/features/term-recount.feature b/features/term-recount.feature index 59b4ad63e..c86c88c9a 100644 --- a/features/term-recount.feature +++ b/features/term-recount.feature @@ -10,16 +10,17 @@ Feature: Recount terms on a taxonomy """ Warning: Taxonomy some-fake-taxonomy does not exist. """ + And the return code should be 0 Scenario: Term recount with a valid taxonomy - When I try `wp term recount category` + When I run `wp term recount category` Then STDOUT should be: """ Success: Updated category term count. """ Scenario: Term recount with a multiple taxonomies - When I try `wp term recount category post_tag` + When I run `wp term recount category post_tag` Then STDOUT should be: """ Success: Updated category term count. diff --git a/features/term.feature b/features/term.feature index be048f9a5..f957ee2a8 100644 --- a/features/term.feature +++ b/features/term.feature @@ -10,6 +10,7 @@ Feature: Manage WordPress terms When I try the previous command again Then STDERR should not be empty + And the return code should be 1 When I run `wp term list post_tag --format=json` Then STDOUT should be JSON containing: @@ -54,6 +55,7 @@ Feature: Manage WordPress terms """ Error: Taxonomy nonexistent_taxonomy doesn't exist. """ + And the return code should be 1 Scenario: Creating/deleting a term When I run `wp term create post_tag 'Test delete term' --slug=test-delete --description='This is a test term to be deleted' --porcelain` @@ -107,6 +109,7 @@ Feature: Manage WordPress terms """ Error: Parent term does not exist. """ + And the return code should be 1 Scenario: Filter terms by term_id When I run `wp term generate category --count=10` diff --git a/features/user-generate.feature b/features/user-generate.feature index cbe263b3c..09a1650f5 100644 --- a/features/user-generate.feature +++ b/features/user-generate.feature @@ -18,7 +18,17 @@ Feature: Generate WP users """ When I try `wp user list --field=ID | xargs wp user delete invalid-user --yes` - And I run `wp user list --format=count` + Then STDOUT should contain: + """ + Success: Removed user + """ + And STDERR should be: + """ + Warning: Invalid user ID, email or login: 'invalid-user' + """ + And the return code should be 0 + + When I run `wp user list --format=count` Then STDOUT should be: """ 0 diff --git a/features/user-import-csv.feature b/features/user-import-csv.feature index 94d570e0e..a6d46f445 100644 --- a/features/user-import-csv.feature +++ b/features/user-import-csv.feature @@ -15,6 +15,7 @@ Feature: Import users from CSV """ Error: Missing file: users-incorrect.csv """ + And the return code should be 1 When I run `wp user import-csv users.csv` Then STDOUT should not be empty @@ -51,10 +52,11 @@ Feature: Import users from CSV """ When I try `wp user import-csv user-invalid.csv` - Then STDERR should contain: + Then STDERR should be: """ - lowercase letters (a-z) and numbers + Warning: Usernames can only contain lowercase letters (a-z) and numbers. """ + And the return code should be 0 When I run `wp user import-csv user-valid.csv` Then STDOUT should not be empty @@ -151,6 +153,7 @@ Feature: Import users from CSV """ Error: Unable to read content from STDIN. """ + And the return code should be 1 When I run `cat users.csv | wp user import-csv -` Then STDOUT should be: diff --git a/features/user-meta.feature b/features/user-meta.feature index b6e49572c..dd15cdc6e 100644 --- a/features/user-meta.feature +++ b/features/user-meta.feature @@ -17,6 +17,7 @@ Feature: Manage user custom fields """ Error: Invalid user ID, email or login: '2' """ + And the return code should be 1 When I run `wp user-meta set admin foo '[ "1", "2" ]' --format=json` Then STDOUT should not be empty diff --git a/features/user.feature b/features/user.feature index 718f70b17..25581803b 100644 --- a/features/user.feature +++ b/features/user.feature @@ -101,6 +101,7 @@ Feature: Manage WordPress users When I try `wp user get bobjones` Then STDERR should not be empty + And the return code should be 1 Scenario: Create new users on multisite Given a WP multisite install @@ -110,6 +111,7 @@ Feature: Manage WordPress users """ lowercase letters (a-z) and numbers """ + And the return code should be 1 When I run `wp user create bobjones bobjones@example.com --display_name="Bob Jones"` Then STDOUT should not be empty @@ -136,18 +138,21 @@ Feature: Manage WordPress users """ Role doesn't exist """ + And the return code should be 1 When I try `wp user set-role 1 edit` Then STDERR should contain: """ Role doesn't exist """ + And the return code should be 1 When I try `wp user remove-role 1 edit` Then STDERR should contain: """ Role doesn't exist """ + And the return code should be 1 When I run `wp user set-role 1 author` Then STDOUT should not be empty @@ -350,6 +355,7 @@ Feature: Manage WordPress users """ Success: User already spammed. """ + And the return code should be 0 When I try `wp user spam {OP_ID} 9999` Then STDOUT should be: diff --git a/src/Comment_Command.php b/src/Comment_Command.php index 76b0b8d2d..043c50cca 100644 --- a/src/Comment_Command.php +++ b/src/Comment_Command.php @@ -428,6 +428,16 @@ private function set_status( $args, $status, $success ) { } } + /** + * Warn if `$_SERVER['SERVER_NAME']` not set as used in email from-address sent to post author in `wp_notify_postauthor()`. + */ + private function check_server_name() { + if ( empty( $_SERVER['SERVER_NAME'] ) ) { + WP_CLI::warning( '`$_SERVER[\'SERVER_NAME\']` not set. Setting to \'example.com\'. Notification email sent to post author may appear to come from \'example.com\'.' ); + $_SERVER['SERVER_NAME'] = 'example.com'; + } + } + /** * Trash a comment. * @@ -523,6 +533,7 @@ public function unspam( $args, $assoc_args ) { * Success: Approved comment 1337. */ public function approve( $args, $assoc_args ) { + $this->check_server_name(); foreach( $args as $id ) { $this->set_status( $id, 'approve', "Approved" ); } @@ -543,6 +554,7 @@ public function approve( $args, $assoc_args ) { * Success: Unapproved comment 1337. */ public function unapprove( $args, $assoc_args ) { + $this->check_server_name(); foreach( $args as $id ) { $this->set_status( $id, 'hold', "Unapproved" ); } diff --git a/src/User_Command.php b/src/User_Command.php index 9673953f7..33e73e1bc 100644 --- a/src/User_Command.php +++ b/src/User_Command.php @@ -1147,10 +1147,7 @@ private function update_msuser_status( $user_ids, $pref, $value ) { $successes++; } - if ( ! $this->chained_command ) { - Utils\report_batch_operation_results( 'user', $verb, count( $user_ids ), $successes, $errors ); - } - + Utils\report_batch_operation_results( 'user', $verb, count( $user_ids ), $successes, $errors ); } } From b83abb958f3189cc86dab9d7245d366de4a3100a Mon Sep 17 00:00:00 2001 From: gitlost Date: Sat, 18 Nov 2017 01:38:09 +0000 Subject: [PATCH 4/6] Set comment_post_ID to 0 if not set; revert message check change in import-csv. --- features/user-import-csv.feature | 5 +++-- src/Comment_Command.php | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/features/user-import-csv.feature b/features/user-import-csv.feature index a6d46f445..69f603358 100644 --- a/features/user-import-csv.feature +++ b/features/user-import-csv.feature @@ -52,9 +52,10 @@ Feature: Import users from CSV """ When I try `wp user import-csv user-invalid.csv` - Then STDERR should be: + # Message changed from "Only lowercase..." to "Usernames can contain only lowercase..." in `wpmu_validate_user_signup()` WP 4.4 https://core.trac.wordpress.org/ticket/33336 + Then STDERR should contain: """ - Warning: Usernames can only contain lowercase letters (a-z) and numbers. + lowercase letters (a-z) and numbers """ And the return code should be 0 diff --git a/src/Comment_Command.php b/src/Comment_Command.php index 043c50cca..565a6a960 100644 --- a/src/Comment_Command.php +++ b/src/Comment_Command.php @@ -69,6 +69,9 @@ public function create( $args, $assoc_args ) { if ( !$post ) { return new WP_Error( 'no_post', "Can't find post $post_id." ); } + } else { + // Make sure it's set for older WP versions else get undefined PHP notice. + $params['comment_post_ID'] = 0; } // We use wp_insert_comment() instead of wp_new_comment() to stay at a low level and @@ -163,7 +166,9 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); } - $comment_post_ID = empty( $assoc_args['post_id'] ) ? 1 : $assoc_args['post_id']; + // Make sure comment_post_ID set for older WP versions else get undefined PHP notice. + $comment_post_ID = isset( $assoc_args['post_id'] ) ? $assoc_args['post_id'] : 0; + $comment_count = wp_count_comments(); $total = (int )$comment_count->total_comments; $limit = $total + $assoc_args['count']; From c7b54bc135f2f2f5ab7fbcfc443c61e7c17f4125 Mon Sep 17 00:00:00 2001 From: gitlost Date: Sat, 18 Nov 2017 10:51:24 +0000 Subject: [PATCH 5/6] Default comment_post_ID to 1 in generate() to avoid notices in old WPs. --- src/Comment_Command.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Comment_Command.php b/src/Comment_Command.php index 565a6a960..8c1b9fae1 100644 --- a/src/Comment_Command.php +++ b/src/Comment_Command.php @@ -128,7 +128,7 @@ public function update( $args, $assoc_args ) { * --- * * [--post_id=] - * : Assign comments to a specific post. + * : Assign comments to a specific post. Defaults to post_id 1. * * [--format=] * : Render output in a particular format. @@ -167,7 +167,7 @@ public function generate( $args, $assoc_args ) { } // Make sure comment_post_ID set for older WP versions else get undefined PHP notice. - $comment_post_ID = isset( $assoc_args['post_id'] ) ? $assoc_args['post_id'] : 0; + $comment_post_ID = isset( $assoc_args['post_id'] ) ? $assoc_args['post_id'] : 1; $comment_count = wp_count_comments(); $total = (int )$comment_count->total_comments; From 9f1575a5c8157e2fabb94e74fa9567f777b1587d Mon Sep 17 00:00:00 2001 From: gitlost Date: Sat, 18 Nov 2017 14:13:22 +0000 Subject: [PATCH 6/6] Default comment post id to 0 (WP 4.4 value). Check SERVER_NAME untrash/unspam also. --- features/comment.feature | 153 +++++++++++++++++++++++++++++---------- src/Comment_Command.php | 13 ++-- 2 files changed, 119 insertions(+), 47 deletions(-) diff --git a/features/comment.feature b/features/comment.feature index 5b32354af..e09c3feb2 100644 --- a/features/comment.feature +++ b/features/comment.feature @@ -156,12 +156,21 @@ Feature: Manage WordPress comments Given I run `wp comment create --comment_post_ID=1 --comment_approved=0 --porcelain` And save STDOUT as {COMMENT_ID} + # With site url set. When I run `wp comment approve {COMMENT_ID} --url=www.example.com` - Then STDOUT should contain: + Then STDOUT should be: """ - Approved comment {COMMENT_ID} + Success: Approved comment {COMMENT_ID}. """ + When I try the previous command again + Then STDERR should be: + """ + Error: Could not update comment status + """ + And STDOUT should be empty + And the return code should be 1 + When I run `wp comment get --field=comment_approved {COMMENT_ID}` Then STDOUT should be: """ @@ -169,9 +178,9 @@ Feature: Manage WordPress comments """ When I run `wp comment unapprove {COMMENT_ID} --url=www.example.com` - Then STDOUT should contain: + Then STDOUT should be: """ - Unapproved comment {COMMENT_ID} + Success: Unapproved comment {COMMENT_ID}. """ When I run `wp comment get --field=comment_approved {COMMENT_ID}` @@ -180,50 +189,40 @@ Feature: Manage WordPress comments 0 """ + # Without site url set. When I try `wp comment approve {COMMENT_ID}` - Then STDOUT should contain: + Then STDOUT should be: """ - Approved comment {COMMENT_ID} + Success: Approved comment {COMMENT_ID}. """ - And STDERR should contain: + And STDERR should be: """ - Warning: `$_SERVER['SERVER_NAME']` not set. Setting to 'example.com'. Notification email sent to post author may appear to come from 'example.com'. + Warning: Site url not set - defaulting to 'example.com'. Any notification emails sent to post author may appear to come from 'example.com'. """ And the return code should be 0 - When I run `wp comment get --field=comment_approved {COMMENT_ID}` - Then STDOUT should be: - """ - 1 - """ - When I try `wp comment unapprove {COMMENT_ID}` - Then STDOUT should contain: + Then STDOUT should be: """ - Unapproved comment {COMMENT_ID} + Success: Unapproved comment {COMMENT_ID}. """ - And STDERR should contain: + And STDERR should be: """ - Warning: `$_SERVER['SERVER_NAME']` not set. Setting to 'example.com'. Notification email sent to post author may appear to come from 'example.com'. + Warning: Site url not set - defaulting to 'example.com'. Any notification emails sent to post author may appear to come from 'example.com'. """ And the return code should be 0 - When I run `wp comment get --field=comment_approved {COMMENT_ID}` - Then STDOUT should be: - """ - 0 - """ - Scenario: Approving/unapproving comments with multidigit comment ID Given I run `wp comment delete $(wp comment list --field=ID)` And I run `wp comment generate --count=10 --quiet` - And I run `wp comment create --porcelain` + And I run `wp comment create --comment_post_ID=1 --porcelain` And save STDOUT as {COMMENT_ID} + # With site url set. When I run `wp comment unapprove {COMMENT_ID} --url=www.example.com` - Then STDOUT should contain: + Then STDOUT should be: """ - Unapproved comment {COMMENT_ID} + Success: Unapproved comment {COMMENT_ID}. """ When I run `wp comment list --format=count --status=approve` @@ -233,9 +232,9 @@ Feature: Manage WordPress comments """ When I run `wp comment approve {COMMENT_ID} --url=www.example.com` - Then STDOUT should contain: + Then STDOUT should be: """ - Approved comment {COMMENT_ID} + Success: Approved comment {COMMENT_ID}. """ When I run `wp comment list --format=count --status=approve` @@ -244,16 +243,40 @@ Feature: Manage WordPress comments 11 """ + # Without site url set. + When I try `wp comment unapprove {COMMENT_ID}` + Then STDOUT should be: + """ + Success: Unapproved comment {COMMENT_ID}. + """ + And STDERR should be: + """ + Warning: Site url not set - defaulting to 'example.com'. Any notification emails sent to post author may appear to come from 'example.com'. + """ + And the return code should be 0 + + When I try `wp comment approve {COMMENT_ID}` + Then STDOUT should be: + """ + Success: Approved comment {COMMENT_ID}. + """ + And STDERR should be: + """ + Warning: Site url not set - defaulting to 'example.com'. Any notification emails sent to post author may appear to come from 'example.com'. + """ + And the return code should be 0 + Scenario: Spam/unspam comments with multidigit comment ID Given I run `wp comment delete $(wp comment list --field=ID)` And I run `wp comment generate --count=10 --quiet` - And I run `wp comment create --porcelain` + And I run `wp comment create --comment_post_ID=1 --porcelain` And save STDOUT as {COMMENT_ID} + # With site url set. When I run `wp comment spam {COMMENT_ID}` - Then STDOUT should contain: + Then STDOUT should be: """ - Marked as spam comment {COMMENT_ID}. + Success: Marked as spam comment {COMMENT_ID}. """ When I run `wp comment list --format=count --status=spam` @@ -262,10 +285,10 @@ Feature: Manage WordPress comments 1 """ - When I run `wp comment unspam {COMMENT_ID}` - Then STDOUT should contain: + When I run `wp comment unspam {COMMENT_ID} --url=www.example.com` + Then STDOUT should be: """ - Unspammed comment {COMMENT_ID}. + Success: Unspammed comment {COMMENT_ID}. """ When I run `wp comment list --format=count --status=spam` @@ -274,14 +297,33 @@ Feature: Manage WordPress comments 0 """ + # Without site url set. + When I run `wp comment spam {COMMENT_ID}` + Then STDOUT should be: + """ + Success: Marked as spam comment {COMMENT_ID}. + """ + + When I try `wp comment unspam {COMMENT_ID}` + Then STDOUT should be: + """ + Success: Unspammed comment {COMMENT_ID}. + """ + And STDERR should be: + """ + Warning: Site url not set - defaulting to 'example.com'. Any notification emails sent to post author may appear to come from 'example.com'. + """ + And the return code should be 0 + Scenario: Trash/untrash comments with multidigit comment ID Given I run `wp comment delete $(wp comment list --field=ID) --force` And I run `wp comment generate --count=10 --quiet` - And I run `wp comment create --porcelain` + And I run `wp comment create --comment_post_ID=1 --porcelain` And save STDOUT as {COMMENT_ID} + # With site url set. When I run `wp comment trash {COMMENT_ID}` - Then STDOUT should contain: + Then STDOUT should be: """ Success: Trashed comment {COMMENT_ID}. """ @@ -292,10 +334,10 @@ Feature: Manage WordPress comments 1 """ - When I run `wp comment untrash {COMMENT_ID}` - Then STDOUT should contain: + When I run `wp comment untrash {COMMENT_ID} --url=www.example.com` + Then STDOUT should be: """ - Untrashed comment {COMMENT_ID}. + Success: Untrashed comment {COMMENT_ID}. """ When I run `wp comment list --format=count --status=trash` @@ -304,6 +346,24 @@ Feature: Manage WordPress comments 0 """ + # Without site url set. + When I run `wp comment trash {COMMENT_ID}` + Then STDOUT should be: + """ + Success: Trashed comment {COMMENT_ID}. + """ + + When I try `wp comment untrash {COMMENT_ID}` + Then STDOUT should be: + """ + Success: Untrashed comment {COMMENT_ID}. + """ + And STDERR should be: + """ + Warning: Site url not set - defaulting to 'example.com'. Any notification emails sent to post author may appear to come from 'example.com'. + """ + And the return code should be 0 + Scenario: Make sure WordPress receives the slashed data it expects When I run `wp comment create --comment_content='My\Comment' --porcelain` Then save STDOUT as {COMMENT_ID} @@ -322,3 +382,16 @@ Feature: Manage WordPress comments """ My\New\Comment """ + + @require-wp-4.4 + Scenario: Approving/unapproving/unspamming/untrashing (approved) comments with no comment post id should not produce PHP notices for WP >= 4.4 + Given I run `wp comment create --comment_approved=0 --porcelain` + And save STDOUT as {COMMENT_ID} + When I run `wp comment approve {COMMENT_ID} --url=www.example.com` + And I run `wp comment unapprove {COMMENT_ID} --url=www.example.com` + + Given I run `wp comment approve {COMMENT_ID} --url=www.example.com` + When I run `wp comment spam {COMMENT_ID} --url=www.example.com` + And I run `wp comment unspam {COMMENT_ID} --url=www.example.com` + And I run `wp comment trash {COMMENT_ID} --url=www.example.com` + And I run `wp comment untrash {COMMENT_ID} --url=www.example.com` diff --git a/src/Comment_Command.php b/src/Comment_Command.php index 8c1b9fae1..5625ad43f 100644 --- a/src/Comment_Command.php +++ b/src/Comment_Command.php @@ -128,7 +128,7 @@ public function update( $args, $assoc_args ) { * --- * * [--post_id=] - * : Assign comments to a specific post. Defaults to post_id 1. + * : Assign comments to a specific post. * * [--format=] * : Render output in a particular format. @@ -155,7 +155,7 @@ public function generate( $args, $assoc_args ) { $defaults = array( 'count' => 100, - 'post_id' => null, + 'post_id' => 0, ); $assoc_args = array_merge( $defaults, $assoc_args ); @@ -166,9 +166,6 @@ public function generate( $args, $assoc_args ) { $notify = \WP_CLI\Utils\make_progress_bar( 'Generating comments', $assoc_args['count'] ); } - // Make sure comment_post_ID set for older WP versions else get undefined PHP notice. - $comment_post_ID = isset( $assoc_args['post_id'] ) ? $assoc_args['post_id'] : 1; - $comment_count = wp_count_comments(); $total = (int )$comment_count->total_comments; $limit = $total + $assoc_args['count']; @@ -176,7 +173,7 @@ public function generate( $args, $assoc_args ) { for ( $i = $total; $i < $limit; $i++ ) { $comment_id = wp_insert_comment( array( 'comment_content' => "Comment {$i}", - 'comment_post_ID' => $comment_post_ID, + 'comment_post_ID' => $assoc_args['post_id'], ) ); if ( 'progress' === $format ) { $notify->tick(); @@ -438,7 +435,7 @@ private function set_status( $args, $status, $success ) { */ private function check_server_name() { if ( empty( $_SERVER['SERVER_NAME'] ) ) { - WP_CLI::warning( '`$_SERVER[\'SERVER_NAME\']` not set. Setting to \'example.com\'. Notification email sent to post author may appear to come from \'example.com\'.' ); + WP_CLI::warning( 'Site url not set - defaulting to \'example.com\'. Any notification emails sent to post author may appear to come from \'example.com\'.' ); $_SERVER['SERVER_NAME'] = 'example.com'; } } @@ -478,6 +475,7 @@ public function trash( $args, $assoc_args ) { * Success: Untrashed comment 1337. */ public function untrash( $args, $assoc_args ) { + $this->check_server_name(); foreach( $args as $id ) { $this->call( $id, __FUNCTION__, 'Untrashed', 'Failed untrashing' ); } @@ -518,6 +516,7 @@ public function spam( $args, $assoc_args ) { * Success: Unspammed comment 1337. */ public function unspam( $args, $assoc_args ) { + $this->check_server_name(); foreach( $args as $id ) { $this->call( $id, __FUNCTION__, 'Unspammed', 'Failed unspamming' ); }