1
0
Fork 0

Add support for "scripts-aliases" in composer.json (#11666)

pull/11699/head
Travis Carden 2023-10-27 05:36:59 -04:00 committed by GitHub
parent cc653161c3
commit aefa46dfba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 3 deletions

View File

@ -441,3 +441,19 @@ The descriptions are used in `composer list` or `composer run -l` commands to
describe what the scripts do when the command is run.
> **Note:** You can only set custom descriptions of custom commands.
## Custom aliases.
You can set custom script aliases with the following in your `composer.json`:
```json
{
"scripts-aliases": {
"phpstan": ["stan", "analyze"]
}
}
```
The aliases provide alternate command names.
> **Note:** You can only set custom aliases of custom commands.

View File

@ -694,6 +694,13 @@
"additionalProperties": {
"type": "string"
}
},
"scripts-aliases": {
"type": ["object"],
"description": "Aliases for custom commands.",
"additionalProperties": {
"type": "array"
}
}
},
"definitions": {

View File

@ -27,11 +27,23 @@ class ScriptAliasCommand extends BaseCommand
private $script;
/** @var string */
private $description;
/** @var string[] */
private $aliases;
public function __construct(string $script, ?string $description)
/**
* @param string[] $aliases
*/
public function __construct(string $script, ?string $description, array $aliases = [])
{
$this->script = $script;
$this->description = $description ?? 'Runs the '.$script.' script as defined in composer.json';
$this->aliases = $aliases;
foreach ($this->aliases as $alias) {
if (!is_string($alias)) {
throw new \InvalidArgumentException('"scripts-aliases" element array values should contain only strings');
}
}
$this->ignoreValidationErrors();
@ -43,6 +55,7 @@ class ScriptAliasCommand extends BaseCommand
$this
->setName($this->script)
->setDescription($this->description)
->setAliases($this->aliases)
->setDefinition([
new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),

View File

@ -249,7 +249,7 @@ class JsonConfigSource implements ConfigSourceInterface
$this->arrayUnshiftRef($args, $config);
$fallback(...$args);
// avoid ending up with arrays for keys that should be objects
foreach (['require', 'require-dev', 'conflict', 'provide', 'replace', 'suggest', 'config', 'autoload', 'autoload-dev', 'scripts', 'scripts-descriptions', 'support'] as $prop) {
foreach (['require', 'require-dev', 'conflict', 'provide', 'replace', 'suggest', 'config', 'autoload', 'autoload-dev', 'scripts', 'scripts-descriptions', 'scripts-aliases', 'support'] as $prop) {
if (isset($config[$prop]) && $config[$prop] === []) {
$config[$prop] = new \stdClass;
}

View File

@ -365,7 +365,9 @@ class Application extends BaseApplication
$description = $composer['scripts-descriptions'][$script];
}
$this->add(new Command\ScriptAliasCommand($script, $description));
$aliases = $composer['scripts-aliases'][$script] ?? [];
$this->add(new Command\ScriptAliasCommand($script, $description, $aliases));
}
}
}

View File

@ -196,6 +196,17 @@ class ConfigValidator
}
}
// report scripts-aliases for non-existent scripts
$scriptAliases = $manifest['scripts-aliases'] ?? [];
foreach ($scriptAliases as $scriptName => $scriptAlias) {
if (!array_key_exists($scriptName, $scripts)) {
$warnings[] = sprintf(
'Aliases for non-existent script "%s" found in "scripts-aliases"',
$scriptName
);
}
}
// check for empty psr-0/psr-4 namespace prefixes
if (isset($manifest['autoload']['psr-0'][''])) {
$warnings[] = "Defining autoload.psr-0 with an empty namespace prefix is a bad idea for performance";

View File

@ -109,6 +109,32 @@ class RunScriptCommandTest extends TestCase
$this->assertStringContainsString('Run the codestyle fixer', $output, 'The custom description for the fix-cs script should be printed');
}
public function testCanDefineAliases(): void
{
$expectedAliases = ['one', 'two', 'three'];
$this->initTempComposer([
'scripts' => [
'test' => '@php test',
],
'scripts-aliases' => [
'test' => $expectedAliases,
],
]);
$appTester = $this->getApplicationTester();
$appTester->run(['command' => 'test', '--help' => true, '--format' => 'json']);
$appTester->assertCommandIsSuccessful();
$output = $appTester->getDisplay();
$array = json_decode($output, true);
$actualAliases = $array['usage'];
array_shift($actualAliases);
$this->assertSame($expectedAliases, $actualAliases, 'The custom aliases for the test command should be printed');
}
public function testExecutionOfCustomSymfonyCommand(): void
{
$this->initTempComposer([

View File

@ -46,6 +46,17 @@ class ConfigValidatorTest extends TestCase
);
}
public function testConfigValidatorWarnsOnScriptAliasForNonexistentScript(): void
{
$configValidator = new ConfigValidator(new NullIO());
[, , $warnings] = $configValidator->validate(__DIR__ . '/Fixtures/composer_scripts-aliases.json');
$this->assertContains(
'Aliases for non-existent script "phpcsxxx" found in "scripts-aliases"',
$warnings
);
}
public function testConfigValidatorWarnsOnUnnecessaryProvideReplace(): void
{
$configValidator = new ConfigValidator(new NullIO());

View File

@ -0,0 +1,10 @@
{
"scripts": {
"test": "phpunit",
"phpcs": "phpcs"
},
"scripts-aliases": {
"test": ["t"],
"phpcsxxx": ["x"]
}
}