Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 15, 2025

Windows PowerShell treats @ as an array expansion operator, requiring awkward quoting: wp "@foo" core version. This PR adds --alias=foo as an alternative to @foo and supports aliases: YAML syntax alongside @foo:.

Changes

YAML Configuration:

  • Configurator::add_alias() - Extracts alias parsing logic, normalizes both @foo: and aliases: { foo: ... } formats
  • Configurator::merge_yml() - Processes new aliases: key
  • Configurator::get_aliases() - Normalizes runtime aliases (from WP_CLI_RUNTIME_ALIAS environment variable) by removing @ prefix for consistency
  • Aliases stored internally without @ prefix
  • CLI_Alias_Command::process_aliases() - Converts all aliases to new aliases: format when writing YAML files for better cross-platform compatibility and consistency

CLI Flag:

  • Added --alias=<name> to config-spec.php
  • Runner::init_config() - Checks for @foo positional arg before parsing, then checks for --alias=foo flag (takes precedence if both provided)
  • Runner::run_alias_group() - Uses --alias=foo internally, displays @foo for consistency
  • Runner::run_ssh_command() - Filters --alias and @alias args from SSH commands

Display & Management:

  • CLI_Alias_Command::list_() - Adds @ prefix back for display
  • CLI_Alias_Command::normalize_alias() - Strips @ prefix for storage
  • CLI_Alias_Command::find_alias_key() - Helper to locate aliases in raw YAML (handles both @foo and aliases: formats)
  • All alias commands (add/update/delete) updated to properly handle both YAML formats
  • CLI_Alias_Command::validate_alias_type() - Updated to properly detect group aliases by checking for numeric array keys instead of @-prefixed values
  • CLI_Alias_Command::build_aliases() - Fixed to preserve existing alias fields during updates and merge with new values, ensuring partial updates don't lose data
  • Completions - Fixed to display @ prefix for aliases in bash completion

Bug Fixes:

  • Fixed alias detection order to preserve backward compatibility with @foo syntax. The @foo positional argument is now detected and removed from $argv before argument parsing, preventing it from being misinterpreted as a command.
  • Fixed YAML operations in CLI alias commands to properly lookup aliases using both @foo: and aliases: { foo: } formats
  • Fixed alias update operations to preserve existing alias fields when updating specific values (e.g., updating --set-path now preserves the existing user field)
  • Fixed YAML file writing to use new aliases: format consistently for better cross-platform compatibility
  • Fixed runtime alias handling to normalize keys from WP_CLI_RUNTIME_ALIAS environment variable for consistency with internal storage
  • Fixed error messages to consistently display @ prefix for user-facing output
  • Fixed group alias validation to properly detect groups by checking for numeric keys instead of @-prefixed values
  • Fixed indentation inconsistency in build_aliases method
  • Added null safety check in validate_alias_type() to prevent preg_grep errors

Examples

YAML:

# Traditional (can still be read)
@prod:
  ssh: user@host:/path

# New syntax (used when writing)
aliases:
  prod:
    ssh: user@host:/path

CLI:

wp @prod core version          # Traditional
wp --alias=prod core version   # New - works in PowerShell without quoting

Both syntaxes are fully interchangeable for reading. All newly written/updated aliases use the new aliases: format for consistency and better cross-platform compatibility. All existing functionality preserved.

Original prompt

This section details on the original issue you should resolve

<issue_title>Support alternative alias syntax for better cross-platform compat</issue_title>
<issue_description>The wp-cli command configuration has some mismatches with Windows Powershell.

e.g. the ALIAS_REGEX constant used to configure remote instances because it uses the @ symbol as a prefix.
@ is used (like the $ character as a variable prefix) to expand the variable (converts a string variable in an array).

const ALIAS_REGEX = '^@[A-Za-z0-9-_\.\-]+$';

Would that be possible to allow overriding the constant with some filter?

Alternative question, why are we using @prod structure to define the aliases in the wp-cli.yml instead of an array of values like disabled_commands or require?</issue_description>

<agent_instructions>Add a new aliases configuration entry in the wp-cli.yml file
Allow to use --alias=foo instead of @foo to use an alias
Keep the classic arg notation working
Works properly with the local and global configs merged together even if both styles are used

Here's a previous attempt from a few years ago to give you some extra context:

diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php
index 575aebee4..fc488902f 100644
--- a/php/WP_CLI/Configurator.php
+++ b/php/WP_CLI/Configurator.php
@@ -96,6 +96,49 @@ private function load_config_spec( $path ) {
 		$this->spec = $config_spec;
 	}
 
+	/**
+	 * Add the given alias to the global config
+	 *
+	 * @param $key
+	 * @param $value
+	 * @param $yml_file_dir
+	 *
+	 * @return void
+	 */
+	private function add_alias( $key, $value, $yml_file_dir ) {
+		if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) {
+			// Remove the @ character from the alias name
+			$key = substr( $key, 1 );
+		}
+
+		$this->aliases[ $key ] = [];
+		$is_alias              = false;
+		foreach ( self::$alias_spec as $i ) {
+			if ( isset( $value[ $i ] ) ) {
+				if ( 'path' === $i && ! isset( $value['ssh'] ) ) {
+					self::absolutize( $value[ $i ], $yml_file_dir );
+				}
+				$this->aliases[ $key ][ $i ] = $value[ $i ];
+				$is_alias                    = true;
+			}
+		}
+
+		// If it's not an alias, it might be a group of aliases.
+		if ( ! $is_alias && is_array( $value ) ) {
+			$alias_group = [];
+			foreach ( $value as $k ) {
+				if ( preg_match( '#' . self::ALIAS_REGEX . '#', $k ) ) {
+					// Remove the @ character from the alias name
+					$alias_group[] = substr( $k, 1 );
+				} elseif ( array_key_exists( $k, $this->aliases ) ) {
+					// Check if the alias has been properly declared before adding it to the group
+					$alias_group[] = $k;
+				}
+			}
+			$this->aliases[ $key ] = $alias_group;
+		}
+	}
+
 	/**
 	 * Get declared configuration values as an array.
 	 *
@@ -257,26 +300,10 @@ public function merge_yml( $path, $current_alias = null ) {
 		$yml_file_dir = $path ? dirname( $path ) : false;
 		foreach ( $yaml as $key => $value ) {
 			if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) {
-				$this->aliases[ $key ] = [];
-				$is_alias              = false;
-				foreach ( self::$alias_spec as $i ) {
-					if ( isset( $value[ $i ] ) ) {
-						if ( 'path' === $i && ! isset( $value['ssh'] ) ) {
-							self::absolutize( $value[ $i ], $yml_file_dir );
-						}
-						$this->aliases[ $key ][ $i ] = $value[ $i ];
-						$is_alias                    = true;
-					}
-				}
-				// If it's not an alias, it might be a group of aliases.
-				if ( ! $is_alias && is_array( $value ) ) {
-					$alias_group = [];
-					foreach ( $value as $k ) {
-						if ( preg_match( '#' . self::ALIAS_REGEX . '#', $k ) ) {
-							$alias_group[] = $k;
-						}
-					}
-					$this->aliases[ $key ] = $alias_group;
+				$this->add_alias( $key, $value, $yml_file_dir );
+			} elseif ( 'aliases' === $key ) {
+				foreach ( $value as $alias => $alias_config ) {
+					$this->add_alias( $alias, $alias_config, $yml_file_dir );
 				}
 			} elseif ( ! isset( $this->spec[ $key ] ) || false === $this->spec[ $key ]['file'] ) {
 				if ( isset( $this->extra_config[ $key ] )
diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php
index 8dc80c80f..6b573bbb4 100644
--- a/php/WP_CLI/Runner.php
+++ b/php/WP_CLI/Runner.php
@@ -507,7 +507,9 @@ private function run_ssh_command( $connection_string ) {
 		}
 
 		foreach ( $wp_args as $k => $v ) {
-			if ( preg_match( '#--ssh=#', $v ) ) {
+			if ( preg_match( '#--ssh=|--alias=#', $v ) ) {
+				unset( $wp_args[ $k ] );
+			} elseif ( preg_match( '#' . Configurator::ALIAS_REGEX . '#', $v ) ) {
 				unset( $wp_args[ $k ] );
 			}
 		}
@@ -973,9 +975,19 @@ public function init_config() {
 
 		$argv = array_slice( $GLOBALS['argv'], 1 );
 
+		// Extract config from CLI args
+		list( $args, $assoc_args, $this->runtime_config ) = $configurator->parse_args( $argv );
+		list( $this->arguments, $this->assoc_args )       = self::back_compat_conversions(
+			$...

</details>

- Fixes wp-cli/wp-cli#5677

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for you](https://github.com/wp-cli/wp-cli/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits November 15, 2025 10:52
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
…s handling

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for alternative alias syntax in wp-cli Support alternative alias syntax for cross-platform compatibility Nov 15, 2025
Copilot AI requested a review from swissspidy November 15, 2025 11:05
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
@codecov
Copy link

codecov bot commented Nov 15, 2025

Codecov Report

❌ Patch coverage is 74.58564% with 46 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
php/WP_CLI/Configurator.php 0.00% 26 Missing ⚠️
php/commands/src/CLI_Alias_Command.php 86.23% 15 Missing ⚠️
php/WP_CLI/Runner.php 86.84% 5 Missing ⚠️

📢 Thoughts on this report? Let us know!

This comment was marked as resolved.

swissspidy and others added 2 commits November 15, 2025 17:26
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@swissspidy

This comment was marked as resolved.

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
@swissspidy

This comment was marked as resolved.

- Update validate_alias_type to use find_alias_key for proper YAML lookup
- Fix build_aliases to remove old key structure before adding updated alias
- Ensure validation happens before modifying aliases array
- Handle both @foo and aliases: formats when removing old keys

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

The build_aliases method creates aliases with normalized keys (without @), but for backward compatibility with existing YAML files and test expectations, we need to add the @ prefix back when writing to YAML files. This ensures that:
- Existing YAML files with @foo: format remain compatible
- New aliases are written with @ prefix
- Tests that expect @foo keys in YAML pass without warnings

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

…iases

Two issues fixed:
1. Alias updates now preserve existing fields - when updating an alias with --set-path, it keeps the existing user field instead of removing it
2. Runtime aliases (WP_CLI_RUNTIME_ALIAS) now normalize keys by removing @ prefix for consistency with internal storage

Changes:
- build_aliases() now preserves existing alias data during updates and merges with new values
- get_aliases() in Configurator normalizes runtime alias keys by removing @ prefix

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI and others added 2 commits December 14, 2025 21:28
Three improvements based on code review:
1. Fixed validate_alias_type to properly detect group aliases - checks for numeric keys instead of @-prefixed values since groups are now stored as ['foo', 'bar'] without @ prefix
2. Fixed indentation inconsistency in build_aliases elseif block
3. Changed process_aliases to write aliases using the new 'aliases:' format instead of @foo: format for better cross-platform compatibility and consistency

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
@swissspidy swissspidy marked this pull request as ready for review December 14, 2025 21:42
@swissspidy swissspidy requested a review from a team as a code owner December 14, 2025 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support alternative alias syntax for better cross-platform compat

2 participants