Skip to content

Add support for Hidden Options in Console #54206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Luc45 opened this issue Mar 8, 2024 · 9 comments · May be fixed by #54439
Open

Add support for Hidden Options in Console #54206

Luc45 opened this issue Mar 8, 2024 · 9 comments · May be fixed by #54439

Comments

@Luc45
Copy link
Contributor

Luc45 commented Mar 8, 2024

Description

Sometimes, we want to deprecate an option but not remove it immediately as to not break CI integration.

It would be ideal to be able to add a "hidden" option that doesn't show up on --help, but still works if you use it.

Example

Suppose we have a command app:send with an existing option --notify. We plan to deprecate --notify but want to maintain it for backward compatibility. The hidden feature could be implemented as follows:

Modifying the addOption Method:

Add an additional argument to the addOption method in Symfony Console. This argument, isHidden, is a boolean indicating whether the option should be hidden from the --help output.

Here's an example of defining the --notify option as a hidden option:

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputOption;

class SendCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('app:send')
            // other options and configuration
            ->addOption(
                'notify',
                null,
                InputOption::VALUE_NONE,
                'Send a notification upon completion.',
                false,
                true // New argument 'isHidden' set to true
            );
    }
}

Behavior with the --help Option:

When a user runs app:send --help, the output will not include the --notify option, as it's marked hidden. However, the option will still function if used explicitly with app:send --notify.

Use case: Deprecating options

The developer can use the option and warn the user about it's deprecation, without breaking backwards compatibility immediately. This is just one example use case.

protected function execute(InputInterface $input, OutputInterface $output)
{
    if ($input->getOption('notify')) {
        $output->writeln('<comment>Warning: The --notify option is deprecated and will be removed in a future version.</comment>');
        // Execute notify functionality
    }

    // Rest of the command execution
}
@Jean-Beru
Copy link
Contributor

Good idea 👍

If the goal is to handle deprecation in input options/arguments, we can add a ?string $deprecationMessage = null argument instead of bool $isHidden. If this argument is set:

  • --help hides the deprecated option/argument (--show-deprecated will display it)
  • trigger a deprecation if this option/argument is used
  • display a warning if this option/argument is used

WDYT ?

@tschmidtdev
Copy link

Sounds useful. If no one is working on it right now, I'll create a PR for that if it's okay. :) I've been working with Symfony for qa couple of time but this would be my first time contributing back ^^ Any support is welcome I want to help more in the feature :)

@chalasr
Copy link
Member

chalasr commented Mar 9, 2024

Given deprecating input options is the main use case, why not deprecate: true directly instead? And make the console in charge of triggering ?
I can also imagine how hidden options could be useful on its own (similar to hidden commands), but I wonder if this shouldn't be 2 distinct features.

@lyrixx
Copy link
Member

lyrixx commented Mar 10, 2024

Instead of adding a other argument, what about using flags instead? It's done for that

@Jean-Beru
Copy link
Contributor

Given deprecating input options is the main use case, why not deprecate: true directly instead? And make the console in charge of triggering ?

It was my first thought but how can we set the deprecation message? It could be useful to give an alternative.

@chalasr
Copy link
Member

chalasr commented Mar 10, 2024

Maybe an InputOption::setDeprecated() method accepting a custom message? Similar to what we have in Config, DependencyInjection and Routing

@Luc45
Copy link
Contributor Author

Luc45 commented Mar 10, 2024

WDYT ?

I see it as a trade-off.

With "deprecations", we are giving an opinionated use for the "hide option" feature, which gives the developers a clear and well-integrated path for deprecations.

With "hide option", we are giving a tool that developers can use as they see fit.

I personally prefer "hide option" for two reasons:

  • It's not complicated to deprecate an option once you have isHidden - you just print a message.
  • We already have setHidden on Command, it would be nice to be consistent.

Although admittedly, we lose some of the opinionated advantages such as --show-deprecated.

What about both?

class SendCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('app:send')
            ->addOption( 'notify-hidden', null, InputOption::VALUE_NONE | InputOption::HIDDEN, 'Send a notification upon completion.', false )
            ->addOption( 'notify-deprecated', null, InputOption::VALUE_NONE | InputOption::DEPRECATED, '[Deprecated since 1.2.3. Will be removed in 2.0] Send a notification upon completion.', false )
    }
}

If using --notify-hidden, just hide it from --help.

If using --notify-deprecated, set it as hidden and print a generic deprecation message when used, such as:

The option "--notify_deprecated" is deprecated.

If running --help -v, it shows the deprecated and hidden options.

PS: I haven't considered deeply if this applies for Arguments as well, I'll leave it to you Symfony People 😄.

@Luc45
Copy link
Contributor Author

Luc45 commented Mar 14, 2024

I'm building a CLI application using Console and I had two more instances where I wished I had hidden options.

  1. Compositing Commands

I'm building a CLI tool that runs tests and spins up custom environments, eg:

  • qit run:e2e

Under the hood, this will call qit env:up with some parameters. I would like to have more options to use when calling it internally, that I might not want to expose to the user.

  1. Option Aliases

Some of the parameters of qit env:up are pluralized, eg:

  • qit env:up --plugins gutenberg --plugins wp-staging --themes storefront --requires my-custom-handler.php

I pluralize it because these options are arrays, and they match what I read from config files (with Serializer, btw), eg:

qit-env.yml

plugins:
  - wp-staging
  - gutenberg
themes:
  - storefront
requires:
  - my-custom-handler.php

Pluralization makes sense on config context, but not on options (array) context, as a user might intuitively use --plugin gutenberg instead.

If I had hidden options, I could programmatically create pluralized/non-pluralized options (where non-pluralized would be hidden).

@flkasper
Copy link

flkasper commented Mar 25, 2024

I am currently working on an implementation based on @Luc45 s idea.

  • InputOption Flags for HIDDEN and DEPRECATED.
  • Deprecation warnings will be printed before calling the execute method.
  • Hide options that are not visible in completion
  • The Help command includes a Hidden Option to print hidden options in the descriptors.
  • The Help command colours deprecated and non-hidden options

The implementation is finished, I just have to adapt and extend the phpunit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants