We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[feature] kfp CLI support 'kfp run get <run_id>' in detailed information
### Feature Area

/area sdk

### What feature would you like to see?
Currently, `kfp run get <run_id>` only shows ["run id", "name", "status", "created at"].
However, user could want to see other information of the run.

### What is the use case or pain point?
For my case, I want to fetch my **run's output metrics** with kfp CLI


### Is there a workaround currently?

Since `kfp.Client()` already have `get_run()` method in sdk, which have all information including metrics of run,
I think the UX is only what matters: Which information would be useful or useless, and how user could select them.

For example, I guess `pipeline_Spec.workflow_manifest` could always be omitted, since nobody wants such information.

Therefore, I think with `click.option('--detail')` in get() method in `pipelines/sdk/python/kfp/cli/run.py` shows all information except `pipeline_Spec.workflow_manifest` in json format would be fine.

However, if there is other suggestions, please let me know.
Also, If you guys are ok, I'd like to took this issue and implement this feature.

---

<!-- Don't delete message below to encourage users to support your feature request! -->
Love this idea? Give it a 👍. We prioritize fulfilling features with the most 👍.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sdk/python/kfp/cli/run.py`
Content:
```
1 # Copyright 2018 The Kubeflow Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 
16 import sys
17 import subprocess
18 import time
19 import json
20 import click
21 import shutil
22 
23 from kfp.cli.output import print_output, OutputFormat
24 
25 
26 @click.group()
27 def run():
28     """manage run resources"""
29     pass
30 
31 
32 @run.command()
33 @click.option('-e', '--experiment-id', help='Parent experiment ID of listed runs.')
34 @click.option('-m', '--max-size', default=100, help='Max size of the listed runs.')
35 @click.pass_context
36 def list(ctx, experiment_id, max_size):
37     """list recent KFP runs"""
38     client = ctx.obj['client']
39     output_format = ctx.obj['output']
40     response = client.list_runs(experiment_id=experiment_id, page_size=max_size, sort_by='created_at desc')
41     if response and response.runs:
42         _print_runs(response.runs, output_format)
43     else:
44         if output_format == OutputFormat.json.name:
45             msg = json.dumps([])
46         else:
47             msg = 'No runs found.'
48         click.echo(msg)
49 
50 
51 @run.command()
52 @click.option('-e', '--experiment-name', required=True, help='Experiment name of the run.')
53 @click.option('-r', '--run-name', help='Name of the run.')
54 @click.option('-f', '--package-file', type=click.Path(exists=True, dir_okay=False),
55               help='Path of the pipeline package file.')
56 @click.option('-p', '--pipeline-id', help='ID of the pipeline template.')
57 @click.option('-n', '--pipeline-name', help='Name of the pipeline template.')
58 @click.option('-w', '--watch', is_flag=True, default=False,
59               help='Watch the run status until it finishes.')
60 @click.option('-v', '--version', help='ID of the pipeline version.')
61 @click.option('-t', '--timeout', default=0, help='Wait for a run to complete until timeout in seconds.', type=int)
62 @click.argument('args', nargs=-1)
63 @click.pass_context
64 def submit(ctx, experiment_name, run_name, package_file, pipeline_id, pipeline_name, watch,
65            timeout, version, args):
66     """submit a KFP run"""
67     client = ctx.obj['client']
68     namespace = ctx.obj['namespace']
69     output_format = ctx.obj['output']
70     if not run_name:
71         run_name = experiment_name
72 
73     if not pipeline_id and pipeline_name:
74         pipeline_id = client.get_pipeline_id(name=pipeline_name)
75 
76     if not package_file and not pipeline_id and not version:
77         click.echo('You must provide one of [package_file, pipeline_id, version].', err=True)
78         sys.exit(1)
79 
80     arg_dict = dict(arg.split('=', maxsplit=1) for arg in args)
81 
82     experiment = client.create_experiment(experiment_name)
83     run = client.run_pipeline(experiment.id, run_name, package_file, arg_dict, pipeline_id,
84                               version_id=version)
85     if timeout > 0:
86         _wait_for_run_completion(client, run.id, timeout, output_format)
87     else:
88         _display_run(client, namespace, run.id, watch, output_format)
89 
90 
91 @run.command()
92 @click.option('-w', '--watch', is_flag=True, default=False,
93               help='Watch the run status until it finishes.')
94 @click.argument('run-id')
95 @click.pass_context
96 def get(ctx, watch, run_id):
97     """display the details of a KFP run"""
98     client = ctx.obj['client']
99     namespace = ctx.obj['namespace']
100     output_format = ctx.obj['output']
101     _display_run(client, namespace, run_id, watch, output_format)
102 
103 
104 def _display_run(client, namespace, run_id, watch, output_format):
105     run = client.get_run(run_id).run
106     _print_runs([run], output_format)
107     if not watch:
108         return
109     argo_path = shutil.which('argo')
110     if not argo_path:
111         raise RuntimeError("argo isn't found in $PATH. It's necessary for watch. "
112                            "Please make sure it's installed and available. "
113                            "Installation instructions be found here - "
114                            "https://github.com/argoproj/argo-workflows/releases")
115 
116     argo_workflow_name = None
117     while True:
118         time.sleep(1)
119         run_detail = client.get_run(run_id)
120         run = run_detail.run
121         if run_detail.pipeline_runtime and run_detail.pipeline_runtime.workflow_manifest:
122             manifest = json.loads(run_detail.pipeline_runtime.workflow_manifest)
123             if manifest['metadata'] and manifest['metadata']['name']:
124                 argo_workflow_name = manifest['metadata']['name']
125                 break
126         if run_detail.run.status in ['Succeeded', 'Skipped', 'Failed', 'Error']:
127             click.echo('Run is finished with status {}.'.format(run_detail.run.status))
128             return
129     if argo_workflow_name:
130         subprocess.run([argo_path, 'watch', argo_workflow_name, '-n', namespace])
131         _print_runs([run], output_format)
132 
133 
134 def _wait_for_run_completion(client, run_id, timeout, output_format):
135     run_detail = client.wait_for_run_completion(run_id, timeout)
136     _print_runs([run_detail.run], output_format)
137 
138 
139 def _print_runs(runs, output_format):
140     headers = ['run id', 'name', 'status', 'created at']
141     data = [[run.id, run.name, run.status, run.created_at.isoformat()] for run in runs]
142     print_output(data, headers, output_format, table_format='grid')
143
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sdk/python/kfp/cli/run.py b/sdk/python/kfp/cli/run.py
--- a/sdk/python/kfp/cli/run.py
+++ b/sdk/python/kfp/cli/run.py
@@ -11,15 +11,15 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
-
 import sys
 import subprocess
 import time
 import json
 import click
 import shutil
+import datetime
 
+import kfp
 from kfp.cli.output import print_output, OutputFormat
 
 
@@ -91,18 +91,31 @@
 @run.command()
 @click.option('-w', '--watch', is_flag=True, default=False,
               help='Watch the run status until it finishes.')
+@click.option('-d', '--detail', is_flag=True, default=False,
+              help='Get detailed information of the run in json format.')
 @click.argument('run-id')
 @click.pass_context
-def get(ctx, watch, run_id):
+def get(ctx, watch, detail, run_id):
     """display the details of a KFP run"""
     client = ctx.obj['client']
     namespace = ctx.obj['namespace']
     output_format = ctx.obj['output']
-    _display_run(client, namespace, run_id, watch, output_format)
+
+    _display_run(client, namespace, run_id, watch, output_format, detail)
 
 
-def _display_run(client, namespace, run_id, watch, output_format):
+def _display_run(client, namespace, run_id, watch, output_format, detail=False):
     run = client.get_run(run_id).run
+
+    if detail:
+        data = {
+            key: value.isoformat() if isinstance(value, datetime.datetime) else value
+            for key, value in run.to_dict().items()
+            if key not in ['pipeline_spec']  # useless but too much detailed field
+        }
+        click.echo(data)
+        return
+
     _print_runs([run], output_format)
     if not watch:
         return

{"golden_diff": "diff --git a/sdk/python/kfp/cli/run.py b/sdk/python/kfp/cli/run.py\n--- a/sdk/python/kfp/cli/run.py\n+++ b/sdk/python/kfp/cli/run.py\n@@ -11,15 +11,15 @@\n # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n # See the License for the specific language governing permissions and\n # limitations under the License.\n-\n-\n import sys\n import subprocess\n import time\n import json\n import click\n import shutil\n+import datetime\n \n+import kfp\n from kfp.cli.output import print_output, OutputFormat\n \n \n@@ -91,18 +91,31 @@\n @run.command()\n @click.option('-w', '--watch', is_flag=True, default=False,\n               help='Watch the run status until it finishes.')\n+@click.option('-d', '--detail', is_flag=True, default=False,\n+              help='Get detailed information of the run in json format.')\n @click.argument('run-id')\n @click.pass_context\n-def get(ctx, watch, run_id):\n+def get(ctx, watch, detail, run_id):\n     \"\"\"display the details of a KFP run\"\"\"\n     client = ctx.obj['client']\n     namespace = ctx.obj['namespace']\n     output_format = ctx.obj['output']\n-    _display_run(client, namespace, run_id, watch, output_format)\n+\n+    _display_run(client, namespace, run_id, watch, output_format, detail)\n \n \n-def _display_run(client, namespace, run_id, watch, output_format):\n+def _display_run(client, namespace, run_id, watch, output_format, detail=False):\n     run = client.get_run(run_id).run\n+\n+    if detail:\n+        data = {\n+            key: value.isoformat() if isinstance(value, datetime.datetime) else value\n+            for key, value in run.to_dict().items()\n+            if key not in ['pipeline_spec']  # useless but too much detailed field\n+        }\n+        click.echo(data)\n+        return\n+\n     _print_runs([run], output_format)\n     if not watch:\n         return\n", "issue": "[feature] kfp CLI support 'kfp run get <run_id>' in detailed information\n### Feature Area\r\n\r\n/area sdk\r\n\r\n### What feature would you like to see?\r\nCurrently, `kfp run get <run_id>` only shows [\"run id\", \"name\", \"status\", \"created at\"].\r\nHowever, user could want to see other information of the run.\r\n\r\n### What is the use case or pain point?\r\nFor my case, I want to fetch my **run's output metrics** with kfp CLI\r\n\r\n\r\n### Is there a workaround currently?\r\n\r\nSince `kfp.Client()` already have `get_run()` method in sdk, which have all information including metrics of run,\r\nI think the UX is only what matters: Which information would be useful or useless, and how user could select them.\r\n\r\nFor example, I guess `pipeline_Spec.workflow_manifest` could always be omitted, since nobody wants such information.\r\n\r\nTherefore, I think with `click.option('--detail')` in get() method in `pipelines/sdk/python/kfp/cli/run.py` shows all information except `pipeline_Spec.workflow_manifest` in json format would be fine.\r\n\r\nHowever, if there is other suggestions, please let me know.\r\nAlso, If you guys are ok, I'd like to took this issue and implement this feature.\r\n\r\n---\r\n\r\n<!-- Don't delete message below to encourage users to support your feature request! -->\r\nLove this idea? Give it a \ud83d\udc4d. We prioritize fulfilling features with the most \ud83d\udc4d.\r\n\n", "before_files": [{"content": "# Copyright 2018 The Kubeflow Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\nimport sys\nimport subprocess\nimport time\nimport json\nimport click\nimport shutil\n\nfrom kfp.cli.output import print_output, OutputFormat\n\n\n@click.group()\ndef run():\n    \"\"\"manage run resources\"\"\"\n    pass\n\n\n@run.command()\n@click.option('-e', '--experiment-id', help='Parent experiment ID of listed runs.')\n@click.option('-m', '--max-size', default=100, help='Max size of the listed runs.')\n@click.pass_context\ndef list(ctx, experiment_id, max_size):\n    \"\"\"list recent KFP runs\"\"\"\n    client = ctx.obj['client']\n    output_format = ctx.obj['output']\n    response = client.list_runs(experiment_id=experiment_id, page_size=max_size, sort_by='created_at desc')\n    if response and response.runs:\n        _print_runs(response.runs, output_format)\n    else:\n        if output_format == OutputFormat.json.name:\n            msg = json.dumps([])\n        else:\n            msg = 'No runs found.'\n        click.echo(msg)\n\n\n@run.command()\n@click.option('-e', '--experiment-name', required=True, help='Experiment name of the run.')\n@click.option('-r', '--run-name', help='Name of the run.')\n@click.option('-f', '--package-file', type=click.Path(exists=True, dir_okay=False),\n              help='Path of the pipeline package file.')\n@click.option('-p', '--pipeline-id', help='ID of the pipeline template.')\n@click.option('-n', '--pipeline-name', help='Name of the pipeline template.')\n@click.option('-w', '--watch', is_flag=True, default=False,\n              help='Watch the run status until it finishes.')\n@click.option('-v', '--version', help='ID of the pipeline version.')\n@click.option('-t', '--timeout', default=0, help='Wait for a run to complete until timeout in seconds.', type=int)\n@click.argument('args', nargs=-1)\n@click.pass_context\ndef submit(ctx, experiment_name, run_name, package_file, pipeline_id, pipeline_name, watch,\n           timeout, version, args):\n    \"\"\"submit a KFP run\"\"\"\n    client = ctx.obj['client']\n    namespace = ctx.obj['namespace']\n    output_format = ctx.obj['output']\n    if not run_name:\n        run_name = experiment_name\n\n    if not pipeline_id and pipeline_name:\n        pipeline_id = client.get_pipeline_id(name=pipeline_name)\n\n    if not package_file and not pipeline_id and not version:\n        click.echo('You must provide one of [package_file, pipeline_id, version].', err=True)\n        sys.exit(1)\n\n    arg_dict = dict(arg.split('=', maxsplit=1) for arg in args)\n\n    experiment = client.create_experiment(experiment_name)\n    run = client.run_pipeline(experiment.id, run_name, package_file, arg_dict, pipeline_id,\n                              version_id=version)\n    if timeout > 0:\n        _wait_for_run_completion(client, run.id, timeout, output_format)\n    else:\n        _display_run(client, namespace, run.id, watch, output_format)\n\n\n@run.command()\n@click.option('-w', '--watch', is_flag=True, default=False,\n              help='Watch the run status until it finishes.')\n@click.argument('run-id')\n@click.pass_context\ndef get(ctx, watch, run_id):\n    \"\"\"display the details of a KFP run\"\"\"\n    client = ctx.obj['client']\n    namespace = ctx.obj['namespace']\n    output_format = ctx.obj['output']\n    _display_run(client, namespace, run_id, watch, output_format)\n\n\ndef _display_run(client, namespace, run_id, watch, output_format):\n    run = client.get_run(run_id).run\n    _print_runs([run], output_format)\n    if not watch:\n        return\n    argo_path = shutil.which('argo')\n    if not argo_path:\n        raise RuntimeError(\"argo isn't found in $PATH. It's necessary for watch. \"\n                           \"Please make sure it's installed and available. \"\n                           \"Installation instructions be found here - \"\n                           \"https://github.com/argoproj/argo-workflows/releases\")\n\n    argo_workflow_name = None\n    while True:\n        time.sleep(1)\n        run_detail = client.get_run(run_id)\n        run = run_detail.run\n        if run_detail.pipeline_runtime and run_detail.pipeline_runtime.workflow_manifest:\n            manifest = json.loads(run_detail.pipeline_runtime.workflow_manifest)\n            if manifest['metadata'] and manifest['metadata']['name']:\n                argo_workflow_name = manifest['metadata']['name']\n                break\n        if run_detail.run.status in ['Succeeded', 'Skipped', 'Failed', 'Error']:\n            click.echo('Run is finished with status {}.'.format(run_detail.run.status))\n            return\n    if argo_workflow_name:\n        subprocess.run([argo_path, 'watch', argo_workflow_name, '-n', namespace])\n        _print_runs([run], output_format)\n\n\ndef _wait_for_run_completion(client, run_id, timeout, output_format):\n    run_detail = client.wait_for_run_completion(run_id, timeout)\n    _print_runs([run_detail.run], output_format)\n\n\ndef _print_runs(runs, output_format):\n    headers = ['run id', 'name', 'status', 'created at']\n    data = [[run.id, run.name, run.status, run.created_at.isoformat()] for run in runs]\n    print_output(data, headers, output_format, table_format='grid')\n", "path": "sdk/python/kfp/cli/run.py"}], "after_files": [{"content": "# Copyright 2018 The Kubeflow Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport sys\nimport subprocess\nimport time\nimport json\nimport click\nimport shutil\nimport datetime\n\nimport kfp\nfrom kfp.cli.output import print_output, OutputFormat\n\n\n@click.group()\ndef run():\n    \"\"\"manage run resources\"\"\"\n    pass\n\n\n@run.command()\n@click.option('-e', '--experiment-id', help='Parent experiment ID of listed runs.')\n@click.option('-m', '--max-size', default=100, help='Max size of the listed runs.')\n@click.pass_context\ndef list(ctx, experiment_id, max_size):\n    \"\"\"list recent KFP runs\"\"\"\n    client = ctx.obj['client']\n    output_format = ctx.obj['output']\n    response = client.list_runs(experiment_id=experiment_id, page_size=max_size, sort_by='created_at desc')\n    if response and response.runs:\n        _print_runs(response.runs, output_format)\n    else:\n        if output_format == OutputFormat.json.name:\n            msg = json.dumps([])\n        else:\n            msg = 'No runs found.'\n        click.echo(msg)\n\n\n@run.command()\n@click.option('-e', '--experiment-name', required=True, help='Experiment name of the run.')\n@click.option('-r', '--run-name', help='Name of the run.')\n@click.option('-f', '--package-file', type=click.Path(exists=True, dir_okay=False),\n              help='Path of the pipeline package file.')\n@click.option('-p', '--pipeline-id', help='ID of the pipeline template.')\n@click.option('-n', '--pipeline-name', help='Name of the pipeline template.')\n@click.option('-w', '--watch', is_flag=True, default=False,\n              help='Watch the run status until it finishes.')\n@click.option('-v', '--version', help='ID of the pipeline version.')\n@click.option('-t', '--timeout', default=0, help='Wait for a run to complete until timeout in seconds.', type=int)\n@click.argument('args', nargs=-1)\n@click.pass_context\ndef submit(ctx, experiment_name, run_name, package_file, pipeline_id, pipeline_name, watch,\n           timeout, version, args):\n    \"\"\"submit a KFP run\"\"\"\n    client = ctx.obj['client']\n    namespace = ctx.obj['namespace']\n    output_format = ctx.obj['output']\n    if not run_name:\n        run_name = experiment_name\n\n    if not pipeline_id and pipeline_name:\n        pipeline_id = client.get_pipeline_id(name=pipeline_name)\n\n    if not package_file and not pipeline_id and not version:\n        click.echo('You must provide one of [package_file, pipeline_id, version].', err=True)\n        sys.exit(1)\n\n    arg_dict = dict(arg.split('=', maxsplit=1) for arg in args)\n\n    experiment = client.create_experiment(experiment_name)\n    run = client.run_pipeline(experiment.id, run_name, package_file, arg_dict, pipeline_id,\n                              version_id=version)\n    if timeout > 0:\n        _wait_for_run_completion(client, run.id, timeout, output_format)\n    else:\n        _display_run(client, namespace, run.id, watch, output_format)\n\n\n@run.command()\n@click.option('-w', '--watch', is_flag=True, default=False,\n              help='Watch the run status until it finishes.')\n@click.option('-d', '--detail', is_flag=True, default=False,\n              help='Get detailed information of the run in json format.')\n@click.argument('run-id')\n@click.pass_context\ndef get(ctx, watch, detail, run_id):\n    \"\"\"display the details of a KFP run\"\"\"\n    client = ctx.obj['client']\n    namespace = ctx.obj['namespace']\n    output_format = ctx.obj['output']\n\n    _display_run(client, namespace, run_id, watch, output_format, detail)\n\n\ndef _display_run(client, namespace, run_id, watch, output_format, detail=False):\n    run = client.get_run(run_id).run\n\n    if detail:\n        data = {\n            key: value.isoformat() if isinstance(value, datetime.datetime) else value\n            for key, value in run.to_dict().items()\n            if key not in ['pipeline_spec']  # useless but too much detailed field\n        }\n        click.echo(data)\n        return\n\n    _print_runs([run], output_format)\n    if not watch:\n        return\n    argo_path = shutil.which('argo')\n    if not argo_path:\n        raise RuntimeError(\"argo isn't found in $PATH. It's necessary for watch. \"\n                           \"Please make sure it's installed and available. \"\n                           \"Installation instructions be found here - \"\n                           \"https://github.com/argoproj/argo-workflows/releases\")\n\n    argo_workflow_name = None\n    while True:\n        time.sleep(1)\n        run_detail = client.get_run(run_id)\n        run = run_detail.run\n        if run_detail.pipeline_runtime and run_detail.pipeline_runtime.workflow_manifest:\n            manifest = json.loads(run_detail.pipeline_runtime.workflow_manifest)\n            if manifest['metadata'] and manifest['metadata']['name']:\n                argo_workflow_name = manifest['metadata']['name']\n                break\n        if run_detail.run.status in ['Succeeded', 'Skipped', 'Failed', 'Error']:\n            click.echo('Run is finished with status {}.'.format(run_detail.run.status))\n            return\n    if argo_workflow_name:\n        subprocess.run([argo_path, 'watch', argo_workflow_name, '-n', namespace])\n        _print_runs([run], output_format)\n\n\ndef _wait_for_run_completion(client, run_id, timeout, output_format):\n    run_detail = client.wait_for_run_completion(run_id, timeout)\n    _print_runs([run_detail.run], output_format)\n\n\ndef _print_runs(runs, output_format):\n    headers = ['run id', 'name', 'status', 'created at']\n    data = [[run.id, run.name, run.status, run.created_at.isoformat()] for run in runs]\n    print_output(data, headers, output_format, table_format='grid')\n", "path": "sdk/python/kfp/cli/run.py"}]}