diff --git a/composer.json b/composer.json
index 1b0cff1..b72a38b 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
"inmarelibero/gitignore-checker": "^1.0.4"
},
"require-dev": {
- "wp-cli/wp-cli-tests": "^4",
+ "wp-cli/wp-cli-tests": "^5",
"wp-cli/scaffold-command": "^2",
"wp-cli/extension-command": "^2"
},
@@ -46,12 +46,14 @@
"behat-rerun": "rerun-behat-tests",
"lint": "run-linter-tests",
"phpcs": "run-phpcs-tests",
+ "phpstan": "run-phpstan-tests",
"phpcbf": "run-phpcbf-cleanup",
"phpunit": "run-php-unit-tests",
"prepare-tests": "install-package-tests",
"test": [
"@lint",
"@phpcs",
+ "@phpstan",
"@phpunit",
"@behat"
]
@@ -59,7 +61,9 @@
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true,
- "johnpbloch/wordpress-core-installer": true
- }
+ "johnpbloch/wordpress-core-installer": true,
+ "phpstan/extension-installer": true
+ },
+ "lock": false
}
}
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 88e4f5d..72fe46e 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -38,7 +38,7 @@
-
+
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..824de93
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,13 @@
+parameters:
+ level: 9
+ paths:
+ - src
+ - dist-archive-command.php
+ scanDirectories:
+ - vendor/wp-cli/wp-cli/php
+ scanFiles:
+ - vendor/php-stubs/wordpress-stubs/wordpress-stubs.php
+ treatPhpDocTypesAsCertain: false
+ ignoreErrors:
+ - identifier: missingType.parameter
+ - identifier: missingType.return
diff --git a/src/Dist_Archive_Command.php b/src/Dist_Archive_Command.php
index 5c8e903..01ca0bb 100644
--- a/src/Dist_Archive_Command.php
+++ b/src/Dist_Archive_Command.php
@@ -77,7 +77,7 @@ public function __invoke( $args, $assoc_args ) {
$this->checker = new GitIgnoreChecker( $source_dir_path, '.distignore' );
$dist_ignore_filepath = $source_dir_path . '/.distignore';
if ( file_exists( $dist_ignore_filepath ) ) {
- $file_ignore_rules = explode( PHP_EOL, file_get_contents( $dist_ignore_filepath ) );
+ $file_ignore_rules = explode( PHP_EOL, (string) file_get_contents( $dist_ignore_filepath ) );
} else {
WP_CLI::warning( 'No .distignore file found. All files in directory included in archive.' );
$file_ignore_rules = [];
@@ -124,6 +124,8 @@ public function __invoke( $args, $assoc_args ) {
chdir( dirname( $source_path ) );
+ $cmd = "zip -r '{$archive_absolute_filepath}' {$archive_output_dir_name}";
+
// If the files are being zipped in place, we need the exclusion rules.
// whereas if they were copied for any reasons above, the rules have already been applied.
if ( $source_path !== $source_dir_path || empty( $file_ignore_rules ) ) {
@@ -175,10 +177,14 @@ function ( $ignored_file ) use ( $source_path ) {
$escape_whitelist = 'targz' === $assoc_args['format'] ? array( '^', '*' ) : array();
WP_CLI::debug( "Running: {$cmd}", 'dist-archive' );
$escaped_shell_command = $this->escapeshellcmd( $cmd, $escape_whitelist );
- $ret = WP_CLI::launch( $escaped_shell_command, false, true );
+
+ /**
+ * @var WP_CLI\ProcessRun $ret
+ */
+ $ret = WP_CLI::launch( $escaped_shell_command, false, true );
if ( 0 === $ret->return_code ) {
$filename = pathinfo( $archive_absolute_filepath, PATHINFO_BASENAME );
- $file_size = $this->get_size_format( filesize( $archive_absolute_filepath ), 2 );
+ $file_size = $this->get_size_format( (int) filesize( $archive_absolute_filepath ), 2 );
WP_CLI::success( "Created {$filename} (Size: {$file_size})" );
} else {
@@ -201,7 +207,7 @@ function ( $ignored_file ) use ( $source_path ) {
private function get_file_paths_and_names( $args, $assoc_args ) {
$source_dir_path = realpath( $args[0] );
- if ( ! is_dir( $source_dir_path ) ) {
+ if ( ! $source_dir_path || ! is_dir( $source_dir_path ) ) {
WP_CLI::error( 'Provided input path is not a directory.' );
}
@@ -239,7 +245,7 @@ private function get_file_paths_and_names( $args, $assoc_args ) {
$destination_dir_path = realpath( $destination_dir_path );
- if ( ! is_dir( $destination_dir_path ) ) {
+ if ( ! $destination_dir_path || ! is_dir( $destination_dir_path ) ) {
WP_CLI::error( "Target directory does not exist: {$destination_dir_path}" );
}
@@ -285,33 +291,42 @@ private function get_version( $source_dir_path ) {
* @link https://developer.wordpress.org/reference/functions/get_file_data/
*/
if ( file_exists( $source_dir_path . '/style.css' ) ) {
- $contents = file_get_contents( $source_dir_path . '/style.css', false, null, 0, 5000 );
+ $contents = (string) file_get_contents( $source_dir_path . '/style.css', false, null, 0, 5000 );
$contents = str_replace( "\r", "\n", $contents );
$pattern = '/^' . preg_quote( 'Version', ',' ) . ':(.*)$/mi';
if ( preg_match( $pattern, $contents, $match ) && $match[1] ) {
- $version = trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $match[1] ) );
+ $version = trim( (string) preg_replace( '/\s*(?:\*\/|\?>).*/', '', $match[1] ) );
}
}
if ( empty( $version ) ) {
- foreach ( glob( $source_dir_path . '/*.php' ) as $php_file ) {
- $contents = file_get_contents( $php_file, false, null, 0, 5000 );
- $version = $this->get_version_in_code( $contents );
- if ( ! empty( $version ) ) {
- $version = trim( $version );
+ foreach ( (array) glob( $source_dir_path . '/*.php' ) as $php_file ) {
+ if ( ! $php_file ) {
+ continue;
+ }
+ $contents = (string) file_get_contents( $php_file, false, null, 0, 5000 );
+ $ver = $this->get_version_in_code( $contents );
+ if ( ! empty( $ver ) ) {
+ $version = trim( $ver );
break;
}
}
}
if ( empty( $version ) && file_exists( $source_dir_path . '/composer.json' ) ) {
- $composer_obj = json_decode( file_get_contents( $source_dir_path . '/composer.json' ) );
- if ( ! empty( $composer_obj->version ) ) {
+ /**
+ * @var null|object{version?: string} $composer_obj
+ */
+ $composer_obj = json_decode( (string) file_get_contents( $source_dir_path . '/composer.json' ) );
+ if ( $composer_obj && ! empty( $composer_obj->version ) ) {
$version = trim( $composer_obj->version );
}
}
if ( ! empty( $version ) && false !== stripos( $version, '-alpha' ) && is_dir( $source_dir_path . '/.git' ) ) {
+ /**
+ * @var WP_CLI\ProcessRun $response
+ */
$response = WP_CLI::launch( "cd {$source_dir_path}; git log --pretty=format:'%h' -n 1", false, true );
$maybe_hash = trim( $response->stdout );
if ( $maybe_hash && 7 === strlen( $maybe_hash ) ) {
@@ -387,7 +402,7 @@ private function get_version_in_docblock( $docblock ) {
* @see https://github.com/phpactor/docblock/blob/master/lib/Parser.php
*
* @param string $docblock Docblock to parse.
- * @return array Associative array of parsed data.
+ * @return array Associative array of parsed data.
*/
private function parse_doc_block( $docblock ) {
$tag_documentor = '{@([a-zA-Z0-9-_\\\]+)\s*?(.*)?}';
@@ -402,7 +417,7 @@ private function parse_doc_block( $docblock ) {
}
}
- $tag_name = strtolower( $matches[1] );
+ $tag_name = trim( isset( $matches[1] ) ? strtolower( $matches[1] ) : '' );
$metadata = trim( isset( $matches[2] ) ? $matches[2] : '' );
$tags[ $tag_name ] = $metadata;
@@ -456,7 +471,6 @@ protected function is_path_contains_symlink( $source_dir_path ) {
);
/**
- * @var RecursiveIteratorIterator $iterator
* @var SplFileInfo $item
*/
foreach ( $iterator as $item ) {
@@ -487,7 +501,6 @@ private function get_file_list( $source_dir_path, $excluded = false ) {
);
/**
- * @var RecursiveIteratorIterator $iterator
* @var SplFileInfo $item
*/
foreach ( $iterator as $item ) {
@@ -499,7 +512,7 @@ private function get_file_list( $source_dir_path, $excluded = false ) {
$included_files[] = $relative_filepath;
}
} catch ( \Inmarelibero\GitIgnoreChecker\Exception\InvalidArgumentException $exception ) {
- if ( $item->isLink() && ! file_exists( readlink( $item->getPathname() ) ) ) {
+ if ( $item->isLink() && ! file_exists( (string) readlink( $item->getPathname() ) ) ) {
WP_CLI::error( "Broken symlink at {$relative_filepath}. Target missing at {$item->getLinkTarget()}." );
} else {
WP_CLI::error( $exception->getMessage() );