Repository: PrefectHQ/prefect

Issue:
Add `--description` to the `prefect deployment build` CLI to allow setting deployment description from CLI
### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar request and didn't find it.
- [X] I searched the Prefect documentation for this feature.

### Prefect Version

2.x

### Describe the current behavior

Currently, the deployment descriptions can be set from Python deployment or the UI.

### Describe the proposed behavior

Add an option to do the same from the CLI using `--description` flag accepting a string

### Example Use

it would be useful to pass custom deployment metadata e.g. from CI/CD 

### Additional context

_No response_


Discussion:

Resolving patch:
diff --git a/src/prefect/cli/deployment.py b/src/prefect/cli/deployment.py
--- a/src/prefect/cli/deployment.py
+++ b/src/prefect/cli/deployment.py
@@ -738,6 +738,15 @@ async def build(
     name: str = typer.Option(
         None, "--name", "-n", help="The name to give the deployment."
     ),
+    description: str = typer.Option(
+        None,
+        "--description",
+        "-d",
+        help=(
+            "The description to give the deployment. "
+            "If not provided, the description will be populated from the flow's description."
+        ),
+    ),
     version: str = typer.Option(
         None, "--version", "-v", help="A version to give the deployment."
     ),
@@ -1002,6 +1011,7 @@ async def build(
     deployment = await Deployment.build_from_flow(
         flow=flow,
         name=name,
+        description=description,
         output=deployment_loc,
         skip_upload=skip_upload,
         apply=False,
diff --git a/src/prefect/deployments.py b/src/prefect/deployments.py
--- a/src/prefect/deployments.py
+++ b/src/prefect/deployments.py
@@ -678,6 +678,7 @@ async def build_from_flow(
         cls,
         flow: Flow,
         name: str,
+        description: str = None,
         output: str = None,
         skip_upload: bool = False,
         ignore_file: str = ".prefectignore",
@@ -691,6 +692,7 @@ async def build_from_flow(
         Args:
             flow: A flow function to deploy
             name: A name for the deployment
+            description (optional): A description for the deployment; defaults to the flow's description
             output (optional): if provided, the full deployment specification will be written as a YAML
                 file in the location specified by `output`
             skip_upload: if True, deployment files are not automatically uploaded to remote storage
@@ -707,7 +709,7 @@ async def build_from_flow(
 
         # note that `deployment.load` only updates settings that were *not*
         # provided at initialization
-        deployment = cls(name=name, **kwargs)
+        deployment = cls(name=name, description=description, **kwargs)
         deployment.flow_name = flow.name
         if not deployment.entrypoint:
             ## first see if an entrypoint can be determined


Test patch:
diff --git a/tests/cli/deployment/test_deployment_build.py b/tests/cli/deployment/test_deployment_build.py
--- a/tests/cli/deployment/test_deployment_build.py
+++ b/tests/cli/deployment/test_deployment_build.py
@@ -462,6 +462,35 @@ def test_name_must_be_provided_by_default(self, dep_path):
         )
 
 
+class TestDescription:
+    @pytest.mark.filterwarnings("ignore:does not have upload capabilities")
+    def test_description_set_correctly(
+        self, patch_import, tmp_path, mock_build_from_flow
+    ):
+        deployment_description = "TEST DEPLOYMENT"
+        output_path = str(tmp_path / "test.yaml")
+        entrypoint = "fake-path.py:fn"
+        cmd = [
+            "deployment",
+            "build",
+            entrypoint,
+            "-n",
+            "TEST",
+            "--description",
+            deployment_description,
+            "-o",
+            output_path,
+        ]
+
+        invoke_and_assert(
+            cmd,
+            expected_code=0,
+        )
+
+        build_kwargs = mock_build_from_flow.call_args.kwargs
+        assert build_kwargs["description"] == deployment_description
+
+
 class TestEntrypoint:
     def test_entrypoint_is_saved_as_relative_path(self, patch_import, tmp_path):
         invoke_and_assert(
diff --git a/tests/test_deployments.py b/tests/test_deployments.py
--- a/tests/test_deployments.py
+++ b/tests/test_deployments.py
@@ -279,6 +279,17 @@ async def test_build_from_flow_sets_flow_name(self, flow_function):
         assert d.flow_name == flow_function.name
         assert d.name == "foo"
 
+    async def test_build_from_flow_sets_description(self, flow_function):
+        description = "test description"
+        d = await Deployment.build_from_flow(
+            flow=flow_function, description=description, name="foo"
+        )
+        assert d.description == description
+
+    async def test_description_defaults_to_flow_description(self, flow_function):
+        d = await Deployment.build_from_flow(flow=flow_function, name="foo")
+        assert d.description == flow_function.description
+
     @pytest.mark.parametrize("skip_upload", [True, False])
     async def test_build_from_flow_sets_path(self, flow_function, skip_upload):
         d = await Deployment.build_from_flow(