Skip to content

[Console] Both ansi and no-ansi return false by default #41794

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

Closed
wants to merge 1 commit into from

Conversation

jderusse
Copy link
Member

Q A
Branch? 5.3
Bug fix? yes
New feature? no
Deprecations? no
Tickets -
License MIT
Doc PR -

In Symfony 5.2, both getOption('ansi') and getOption('no-ansi') returned false.
Since the option is now negatable, we can not keep the same behavior, the value returned should be either null, true/false or false/true.

This PR returns false when a negatable option has a default value null.

I'm not 100% convinced by this, as we lost null behavior.... Maybe we should allow 5 differents values null, true/false, false/true, true/true, false/false

@carsonbot

This comment has been minimized.

@carsonbot carsonbot changed the title Both ansi and no-ansi return false by default [Console] Both ansi and no-ansi return false by default Jun 23, 2021
@jderusse jderusse marked this pull request as draft July 6, 2021 15:10
@jderusse jderusse marked this pull request as ready for review September 21, 2021 13:18
@carsonbot

This comment has been minimized.

@jderusse
Copy link
Member Author

In summary:

before 5.2, both --ansi and --no-ansi returned the same false default value.
Since we introduced the Negatable option, --no-ansi is always ! --ansi (true by default) which broke some applications that expect it to have a default false

Having 3 states for a negatable option make sense: for instance

  • true: user asked to enable it
  • false: user asked to disabled it
  • null: let the application choose the best solution

How can we fix the --ansi option issue @symfony/mergers ?

  1. do nothing

😐 We believe that --ansi should default to false and no-ansi to true
👎 Still a BC break since 5.3.0 (see comments in #41723)

  1. switch default to --ansi = null

👍 the cleanest way to say choose the best for the user.
👎 But a BC break for app relying on false with strict comparison getOption('ansi') === false

  1. switch default to --ansi = null BUT option returns false in such case.

This is the behavior of this PR, and I'm not sure to like it.

👍 Restore the behavior of 5.2 and fix the BC
👎 New BC for people that use null default since 5.3
👎 This brokes the case "let the application choose the best solution"

  1. add new values for the Negatable default: Negatable::DEFAULT_TRUE_TRUE, Negatable::DEFAULT_TRUE_FALSE, Negatable::DEFAULT_FALSE_TRUE, Negatable::DEFAULT_FALSE_FALSE that let people configure their option with fine grain for both positive and negative case.

👍 Fix issue in 5.2
👎 Ugly interface and more complex

@kbond
Copy link
Member

kbond commented Nov 20, 2021

This brokes the case "let the application choose the best solution"

How so? Isn't not passing --ansi/--no-ansi to let the application decide the 5.2 behaviour? I was thinking within the context of $output->isDecorated()

@wouterj
Copy link
Member

wouterj commented Nov 20, 2021

My personal opinion: 6 months have past since this BC break, so is it really worth to still complicate the API to fix it? (imho, everything different than the current behavior is less expected)
This can be fixed by Thinker by checking === null when Symfony 5.3+ is used. It's unfortunate that this BC break has made it in a stable release, but I'm not sure there is anything to do about it now (except from maybe documenting this more clearly in the Console CHANGELOG)

This is yet another example of how everyone can improve Symfony (and indirectly many projects not related to Symfony but using it's components) by testing out pre-releases.

@jderusse
Copy link
Member Author

This can be fixed by Thinker by checking === null when Symfony 5.3+ is used

this is the option 2.

At the moment, they can not know if user choose --no-ansi or if symfony used the default value.

@wouterj
Copy link
Member

wouterj commented Nov 20, 2021

So, to make it clear, this is what I would expect (and IIRC, this is the current behavior?)

option passed ansi value
--ansi --ansi = true
--no-ansi = false
--no-ansi --ansi = false
--no-ansi = true
nothing --ansi = null
--no-ansi = null

But apps should rely on getOption('ansi') only: true = users wants it, false = user doesn't want it, null = decide what's best.

@kbond
Copy link
Member

kbond commented Nov 20, 2021

The current 5.3 behaviour is as follows:

option passed ansi value
--ansi --ansi = true
--no-ansi = false
--no-ansi --ansi = false
--no-ansi = true
nothing --ansi = false
--no-ansi = true

And in 5.2 and lower:

option passed ansi value
--ansi --ansi = true
--no-ansi = false
--no-ansi --ansi = false
--no-ansi = true
nothing --ansi = false
--no-ansi = false

With this PR, the behaviour is the same as 5.2. Difference is getOptions()['ansi'] === null instead of false. Am I correct here @jderusse?

@jderusse
Copy link
Member Author

Yes, @kbond is right.

the current behavior of negatable option (when user did not enter a flag)

default value ansi value
true --foo = true
--no-foo = false
false --foo = false
--no-foo = true
null --foo = null
--no-foo = null

BUT --ansi is configured with default false

Switching to null could be the right thing to do, but might be a BC break...

with my PR, the behavior will be

default value ansi value
true --foo = true
--no-foo = false
false --foo = false
--no-foo = true
null --foo = false
--no-foo = false

That will fix the issue for ansi. But have 2 drawback for other people:

  • BC break for people that rely on having null
  • no easy way to check if users did not provide an option (in fack, if both foo and no-foo are identical it means the user did not choose one.. but that's ugly)

@ogizanagi
Copy link
Contributor

ogizanagi commented Nov 20, 2021

Switching to null could be the right thing to do, but might be a BC break...

So option 2, right? My preference goes to this, since the BC break looks pretty mitigated to me and the fact it seems both the cleanest and simplest way to have an "auto" mode where the app is in charge of choosing the solution.

@kbond
Copy link
Member

kbond commented Nov 20, 2021

Using the standard negatable behaviour (option 2) is my preference as well.

Generally, I think apps should use $output->isDecorated() instead of checking the ansi option directly.

ogizanagi added a commit that referenced this pull request Nov 22, 2021
This PR was merged into the 5.3 branch.

Discussion
----------

[Console] Default ansi option to null

| Q             | A
| ------------- | ---
| Branch?       | 5.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

This PR is an alternative to #41794 (see comment for the reasoning of this PR) to fixes laravel/tinker#127

It defaults the negatable option `--ansi` to null

For the recall, having default null is interpreted like this:

| flag passed | getOption(??) return |
| --- | --- |
| `--ansi` | `ansi = true`<br>`no-ansi = false` |
| `--no-ansi` | `ansi = false`<br>`no-ansi = true` |
| nothing | `ansi = null`<br>`no-ansi = null` |

This could be a BC break for people that use strict comparison `getOption('ansi') === false`
But:
- Provide a compatible code for people that cast to bool or use weak comparison
- It fixes the issue by letting know if the option has been defined by the user or is the default value (null)

Here is a summary of the changes

| call | 5.2 | 5.3 | this PR |
| -- | --- | --- | --- |
getOption('ansi') | false | false | null |
getOption('no-ansi') | false | true | null |

Commits
-------

8b45280 Default ansi option to null
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.

6 participants