Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions features/package-install.feature
Original file line number Diff line number Diff line change
Expand Up @@ -1262,3 +1262,33 @@ Feature: Install WP-CLI packages
Error: ZipArchive failed to unzip 'package-dir/zero.zip': Not a zip archive (19).
"""
And STDOUT should be empty

Scenario: Install a package with --no-interaction flag
Given an empty directory
And a composer.json file:
"""
{
"repositories": {
"test" : {
"type": "path",
"url": "./dummy-package/"
},
"wp-cli": {
"type": "composer",
"url": "https://wp-cli.org/package-index/"
}
}
}
"""
And a dummy-package/composer.json file:
"""
{
"name": "wp-cli/restful",
"description": "Test package for no-interaction flag"
}
"""
When I run `WP_CLI_PACKAGES_DIR=. wp package install wp-cli/restful --no-interaction`
Then STDOUT should contain:
"""
Success: Package installed
"""
20 changes: 20 additions & 0 deletions features/package-update.feature
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,23 @@ Feature: Update WP-CLI packages
"""
Success: Packages updated.
"""

Scenario: Update packages with --no-interaction flag
Given an empty directory

When I run `wp package install danielbachhuber/wp-cli-reset-post-date-command`
Then STDOUT should contain:
"""
Success: Package installed.
"""

When I run `wp package update --no-interaction`
Then STDOUT should contain:
"""
Using Composer to update packages...
"""
And STDOUT should contain:
"""
Packages updated.
"""
And STDERR should be empty
19 changes: 19 additions & 0 deletions features/package.feature
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,25 @@ Feature: Manage WP-CLI packages
{NO_SUCH_PACKAGE_COMPOSER_JSON}
"""

Scenario: Uninstall a package with --no-interaction flag
Given an empty directory

When I run `wp package install runcommand/hook`
Then STDERR should be empty

When I run `wp package uninstall runcommand/hook --no-interaction`
Then STDERR should be empty
And STDOUT should contain:
"""
Success: Uninstalled package.
"""

When I run `wp package list`
Then STDOUT should not contain:
"""
runcommand/hook
"""

Scenario: List packages with --skip-update-check flag
Given an empty directory

Expand Down
53 changes: 50 additions & 3 deletions src/Package_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ public function browse( $_, $assoc_args ) {
* [--insecure]
* : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack.
*
* [--interaction]
* : Control interactive mode. Use `--no-interaction` to disable prompts (interactive by default). Useful for scripting.
*
* ## EXAMPLES
*
* # Install a package hosted at a git URL.
Expand All @@ -216,7 +219,12 @@ public function browse( $_, $assoc_args ) {
public function install( $args, $assoc_args ) {
list( $package_name ) = $args;

$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
$interaction = (bool) Utils\get_flag_value( $assoc_args, 'interaction', true );

if ( ! $interaction ) {
$this->set_non_interactive_mode();
}

$this->set_composer_auth_env_var();
$git_package = false;
Expand Down Expand Up @@ -514,6 +522,11 @@ public function path( $args ) {
/**
* Updates all installed WP-CLI packages to their latest version.
*
* ## OPTIONS
*
* [--interaction]
* : Boolean flag that controls interactive mode (enabled by default). Use `--no-interaction` to disable prompts, which is useful for scripting.
*
* ## EXAMPLES
*
* $ wp package update
Expand All @@ -529,8 +542,17 @@ public function path( $args ) {
* Generating autoload files
* ---
* Success: Packages updated.
*
* @param array $_ Unused positional arguments (none expected).
* @param array $assoc_args Associative array of options.
*/
public function update() {
public function update( $_, $assoc_args = [] ) {
$interaction = (bool) Utils\get_flag_value( $assoc_args, 'interaction', true );

if ( ! $interaction ) {
$this->set_non_interactive_mode();
}

$this->set_composer_auth_env_var();
$composer = $this->get_composer();

Expand Down Expand Up @@ -573,6 +595,9 @@ public function update() {
* [--insecure]
* : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack.
*
* [--interaction]
* : Control interactive prompts. Use `--no-interaction` to disable interactive questions (useful for scripting).
*
* ## EXAMPLES
*
* # Uninstall package.
Expand All @@ -585,7 +610,12 @@ public function update() {
public function uninstall( $args, $assoc_args ) {
list( $package_name ) = $args;

$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
$insecure = (bool) Utils\get_flag_value( $assoc_args, 'insecure', false );
$interaction = Utils\get_flag_value( $assoc_args, 'interaction', true );

if ( ! $interaction ) {
$this->set_non_interactive_mode();
}

$this->set_composer_auth_env_var();
$package = $this->get_installed_package_by_name( $package_name );
Expand Down Expand Up @@ -1495,4 +1525,21 @@ private function get_github_default_branch( $package_name, $insecure = false ) {

return $default_branch;
}

/**
* Sets environment variables to enable non-interactive mode.
*
* This prevents Git from prompting for credentials (e.g., SSH passwords),
* which is useful for scripting and automation.
*
* Note: This uses putenv() which affects the entire PHP process, including
* any Git operations spawned by Composer. This is intentional to ensure
* non-interactive behavior propagates to all child processes.
*/
private function set_non_interactive_mode() {
// Prevent Git from prompting for credentials
putenv( 'GIT_TERMINAL_PROMPT=0' );
// Prevent SSH from prompting for passwords
putenv( 'GIT_SSH_COMMAND=ssh -o BatchMode=yes' );
}
}