Repository: pallets/click (python)

Issue:
Deprecated notice in help text can be hard to see
The current `(DEPRECATED)` deprecation notice added to help text can be hard to see plainly since it can't consider the existing format of the help text.

For example:  I use sphinx style formatting in my help text and if this help text ends with a Note block like below:

```python
def encrypt(ctx, **kwargs):
    """Encrypt archives.

    .. Note::

        Here is a notice.
    """
```

Then a deprecation notice would append to the Note block, making it look like part of the Note and not that the command itself is deprecated.

```shell
Usage: cmd encrypt [OPTIONS]

  Encrypt archives.

  .. Note::

      Here is a notice. (DEPRECATED)
```

I would have expected the deprecation notice to be at the top of my help text making it clear to the user that this command is deprecated.  Or at the least a couple a new lines added to differentiate the notice from any existing help text.

Environment:

- Python version: Python 3.7.9
- Click version: click==7.1.2


Pull request:
Deprecation notice now appears at the top of the help text
This PR makes the deprecation notice appear at the beginning of the help text.

- fixes #1791

Checklist:

- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 4f0dfb9..9db1566 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -189,6 +189,9 @@ Unreleased
     store information. :issue:`1739`
 -   ``Path`` ``resolve_path`` resolves symlinks on Windows Python < 3.8.
     :issue:`1813`
+-   Command deprecation notice appears at the start of the help text, as
+    well as in the short help. The notice is not in all caps.
+    :issue:`1791`
 
 
 Version 7.1.2
diff --git a/src/click/core.py b/src/click/core.py
index f3192c5..17cfc3a 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -40,14 +40,6 @@ _missing = object()
 SUBCOMMAND_METAVAR = "COMMAND [ARGS]..."
 SUBCOMMANDS_METAVAR = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..."
 
-DEPRECATED_HELP_NOTICE = " (DEPRECATED)"
-DEPRECATED_INVOKE_NOTICE = "DeprecationWarning: The command {name} is deprecated."
-
-
-def _maybe_show_deprecated_notice(cmd):
-    if cmd.deprecated:
-        echo(style(DEPRECATED_INVOKE_NOTICE.format(name=cmd.name), fg="red"), err=True)
-
 
 def _fast_exit(code):
     """Low-level exit that skips Python's cleanup but speeds up exit by
@@ -1193,12 +1185,15 @@ class Command(BaseCommand):
         """Gets short help for the command or makes it by shortening the
         long help string.
         """
-        return (
-            self.short_help
-            or self.help
-            and make_default_short_help(self.help, limit)
-            or ""
-        )
+        text = self.short_help or ""
+
+        if not text and self.help:
+            text = make_default_short_help(self.help, limit)
+
+        if self.deprecated:
+            text = f"(Deprecated) {text}"
+
+        return text.strip()
 
     def format_help(self, ctx, formatter):
         """Writes the help into the formatter if it exists.
@@ -1219,17 +1214,16 @@ class Command(BaseCommand):
 
     def format_help_text(self, ctx, formatter):
         """Writes the help text to the formatter if it exists."""
-        if self.help:
-            formatter.write_paragraph()
-            with formatter.indentation():
-                help_text = self.help
-                if self.deprecated:
-                    help_text += DEPRECATED_HELP_NOTICE
-                formatter.write_text(help_text)
-        elif self.deprecated:
+        text = self.help or ""
+
+        if self.deprecated:
+            text = f"(Deprecated) {text}"
+
+        if text:
             formatter.write_paragraph()
+
             with formatter.indentation():
-                formatter.write_text(DEPRECATED_HELP_NOTICE)
+                formatter.write_text(text)
 
     def format_options(self, ctx, formatter):
         """Writes all the options into the formatter if they exist."""
@@ -1275,7 +1269,15 @@ class Command(BaseCommand):
         """Given a context, this invokes the attached callback (if it exists)
         in the right way.
         """
-        _maybe_show_deprecated_notice(self)
+        if self.deprecated:
+            echo(
+                style(
+                    f"DeprecationWarning: The command {self.name!r} is deprecated.",
+                    fg="red",
+                ),
+                err=True,
+            )
+
         if self.callback is not None:
             return ctx.invoke(self.callback, **ctx.params)
 


Test patch:
diff --git a/tests/test_commands.py b/tests/test_commands.py
index c8da4ce..205e0f8 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -297,14 +297,14 @@ def test_deprecated_in_help_messages(runner):
         pass
 
     result = runner.invoke(cmd_with_help, ["--help"])
-    assert "(DEPRECATED)" in result.output
+    assert "(Deprecated)" in result.output
 
     @click.command(deprecated=True)
     def cmd_without_help():
         pass
 
     result = runner.invoke(cmd_without_help, ["--help"])
-    assert "(DEPRECATED)" in result.output
+    assert "(Deprecated)" in result.output
 
 
 def test_deprecated_in_invocation(runner):