From d0d216cd74be3fef17e675b5db4f37dd9414e872 Mon Sep 17 00:00:00 2001 From: Aaron Pham <29749331+aarnphm@users.noreply.github.com> Date: Tue, 12 Jul 2022 17:31:17 -0700 Subject: [PATCH] feat: adding new issue templates format + `bentoml env` (#2689) * feat: adding new issue templates format update some of the comments from PULL_REQUEST_TEMPLATE to introduce and encourage community members to contribute more Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * fix: formats Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * style: update formatting Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: update configs Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: fix templates Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * fix: templates Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: updates bug_report Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: udpates Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: updates comments for Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: updates field with placeholer for pip freeze Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: address --env changes Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: updates yamllint Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * feat: better env commands Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: updates naming Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * revert: changes Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: updates issue templates Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * revert: changes from main Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: raise exception earlier Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: migrate to its own file Signed-off-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: Apply suggestions from code review Co-authored-by: Sauyon Lee <2347889+sauyon@users.noreply.github.com> * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update .github/ISSUE_TEMPLATE/config.yml Co-authored-by: Sauyon Lee <2347889+sauyon@users.noreply.github.com> Co-authored-by: Sean Sheng --- .github/ISSUE_TEMPLATE/bug_report.md | 59 ----------- .github/ISSUE_TEMPLATE/bug_report.yml | 74 ++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 12 ++- .github/ISSUE_TEMPLATE/feature_request.md | 20 ---- .github/ISSUE_TEMPLATE/feature_request.yml | 35 +++++++ .github/PULL_REQUEST_TEMPLATE.md | 81 ++++++++------- .github/workflows/codeql-analysis.yml | 22 ++--- .yamllint.yml | 3 - bentoml/_internal/cli/__init__.py | 76 +------------- bentoml/_internal/cli/bento_management.py | 5 +- bentoml/_internal/cli/env.py | 110 +++++++++++++++++++++ bentoml/_internal/cli/model_management.py | 6 +- bentoml/_internal/utils/__init__.py | 3 + 13 files changed, 298 insertions(+), 208 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 bentoml/_internal/cli/env.py diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 84777969624..00000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -name: Bug Report -about: Create a report to help us improve -title: '' -labels: 'bug' -assignees: '' - ---- - -**Describe the bug** - - - -**To Reproduce** - - -**Expected behavior** - - -**Screenshots/Logs** - - - -**Environment:** - - OS: [e.g. MacOS 10.14.3] - - Python Version [e.g. Python 3.7.1] - - BentoML Version [e.g. BentoML-0.8.6] - - -**Additional context** - \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000000..88fd817147e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,74 @@ +name: 🐛 Bug Report +description: Create a bug report to help us improve BentoML. +title: "bug: " +labels: ["bug"] +body: + - type: markdown + id: issue-already-exists + attributes: + value: | + Please search to see if an issue already exists for the bug you encountered. + See [Searching Issues and Pull Requests](https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests) for how to use the GitHub search bar and filters. + - type: textarea + id: describe-the-bug + validations: + required: true + attributes: + label: Describe the bug + description: Please provide a clear and concise description about the problem you ran into. + placeholder: This happened when I... + - type: textarea + id: to-reproduce + validations: + required: false + attributes: + label: To reproduce + description: | + Please provide a code sample or a code snipet to reproduce said problem. If you have code snippets, error messages, stack trace please also provide them here. + + **IMPORTANT**: make sure to use [code tag](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) to correctly format your code. Screenshot is helpful but don't use it for code snippets as it doesn't allow others to copy-and-paste your code. + + To give us more information for diagnosing the issue, make sure to enable debug logging: + + Enable via environment variable, e.g.: + ```bash + BENTOML_DEBUG=TRUE bentoml serve ... + ``` + + Or set debug logging in your Python code: + ```python + import logging + + bentoml_logger = logging.getLogger("bentoml") + bentoml_logger.setLevel(logging.DEBUG) + ``` + + For BentoML CLI commands, simply add the `--verbose` flag, e.g.: + ```bash + bentoml serve service.py:svc --verbose + ``` + placeholder: | + Steps to reproduce the bug: + + 1. Provide '...' + 2. Run '...' + 3. See error + - type: textarea + id: expected-behavior + validations: + required: false + attributes: + label: Expected behavior + description: "A clear and concise description of what you would expect to happen." + - type: textarea + id: environment-info + attributes: + label: Environment + description: | + Please share your environment with us. You should run `bentoml env` and paste the result here. + placeholder: | + bentoml: ... + python: ... + platform: ... + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index bb5c0379c69..3cf5b43467d 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,10 +1,18 @@ +blank_issues_enabled: true +version: 2.1 contact_links: + - name: BentoML's Documentation + url: https://docs.bentoml.org/en/latest/ + about: For more information about BentoML's tutorials, guides, API references and architectures deep-dive. - name: BentoML Discussions url: https://github.com/bentoml/BentoML/discussions about: Please ask general questions here. - name: BentoML Slack Community url: https://join.slack.bentoml.org - about: For connecting with others in the community + about: For connecting with others in the community. - name: BentoML Enterprise Support url: contact@bentoml.ai - about: Contact the BentoML team and learn more + about: Contact the BentoML team for support. + - name: BentoML Blog + url: modelserving.com + about: Read the latest blogs/updates from community and the BentoML team. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 2c94c5a0da5..00000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature Request -about: Suggest a new feature for BentoML -title: '' -labels: 'new feature' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** - - -**Describe the solution you'd like** - - -**Describe alternatives you've considered** - - -**Additional context** - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000000..143f426b3b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,35 @@ +name: 🚀 Feature Request +description: Submit a proposal/request for new BentoML feature. +title: "feature: " +labels: ["new-feature", "enhancement"] +body: +- type: textarea + id: feature-request + validations: + required: true + attributes: + label: Feature request + description: | + A clear and concise description of the feature request. + placeholder: | + I would like it if... +- type: textarea + id: motivation + validations: + required: false + attributes: + label: Motivation + description: | + Please outline the motivation for this feature request. Is your feature request related to a problem? e.g., I'm always frustrated when [...]. + If this is related to another issue, please link here too. + If you have a current workaround, please also provide it here. + placeholder: | + This feature would solve ... +- type: textarea + id: other + attributes: + label: Other + description: | + Is there any way that you could help, e.g. by submitting a PR? Please make sure to read the [contributing guidelines](https://github.com/bentoml/BentoML/blob/main/CONTRIBUTING.md) as well as [development guidelines](https://github.com/bentoml/BentoML/blob/main/DEVELOPMENT.md). + placeholder: | + I would love to contribute ... diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b1948c11f87..c6c09949e76 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,44 +1,59 @@ - - -## Description - - +Describe your changes in detail. Attach screenshots here if appropriate. -## Motivation and Context - - - +Once you're done with this, someone from BentoML team or community member will help review your PR (see "Who can help review?" section for potential reviewers.). If no one has reviewed your PR after a week have passed, don't hesitate to post a new comment and ping @-the same person. Notifications sometimes get lost 🥲. +--> -## How Has This Been Tested? - - - + +Fixes #(issue) -## Checklist: +## Before submitting: -- [ ] My code follows the bentoml code style, both `make format` and - `make lint` script have passed - ([instructions](https://github.com/bentoml/BentoML/blob/master/DEVELOPMENT.md#style-check-and-auto-formatting-your-code)). -- [ ] My change reduces project test coverage and requires unit tests to be added -- [ ] I have added unit tests covering my code change -- [ ] My change requires a change to the documentation -- [ ] I have updated the documentation accordingly \ No newline at end of file +- [ ] Does the Pull Request follow [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/#summary) naming? Here are [GitHub's +guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) on how to create a pull request. +- [ ] Does the code follow BentoML's code style, both `make format` and `make lint` script have passed ([instructions](https://github.com/bentoml/BentoML/blob/main/DEVELOPMENT.md#style-check-auto-formatting-type-checking))? +- [ ] Did you read through [contribution guidelines](https://github.com/bentoml/BentoML/blob/main/CONTRIBUTING.md#ways-to-contribute) and follow [development guidelines](https://github.com/bentoml/BentoML/blob/main/DEVELOPMENT.md#start-developing)? +- [ ] Did your changes require updates to the documentation? Have you updated + those accordingly? Here are [documentation guidelines](https://github.com/bentoml/BentoML/tree/main/docs) and [tips on writting docs](https://github.com/bentoml/BentoML/tree/main/docs#writing-documentation). +- [ ] Did you write tests to cover your changes? + +## Who can help review? + +Feel free to tag members/contributors who can help review your PR. + diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 603a1a03b2a..e33be8f7c0e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,17 +24,17 @@ jobs: language: [ 'python' ] steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v2 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.yamllint.yml b/.yamllint.yml index 238406b25dd..879282bbf3f 100644 --- a/.yamllint.yml +++ b/.yamllint.yml @@ -23,8 +23,5 @@ rules: level: warning hyphens: level: warning - indentation: - level: warning - indent-sequences: consistent line-length: disable truthy: disable diff --git a/bentoml/_internal/cli/__init__.py b/bentoml/_internal/cli/__init__.py index 55140b9ac31..c510afd6da9 100644 --- a/bentoml/_internal/cli/__init__.py +++ b/bentoml/_internal/cli/__init__.py @@ -1,91 +1,21 @@ from __future__ import annotations -import os -import sys -import shutil -import typing as t -import platform -import subprocess -from gettext import gettext - import click import psutil from bentoml import __version__ as BENTOML_VERSION +from .env import add_env_command from .yatai import add_login_command -from ..utils.pkg import get_pkg_version -from ..utils.pkg import PackageNotFoundError from .click_utils import BentoMLCommandGroup from .bento_server import add_serve_command from .containerize import add_containerize_command from .bento_management import add_bento_management_commands from .model_management import add_model_management_commands -FC = t.TypeVar("FC", bound=t.Union[t.Callable[..., t.Any], click.Command]) - - -def env_option(**kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--env`` option which immediately prints environment info for debugging purposes. - - :param param_decls: One or more option names. Defaults to the single - value ``"--help"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ - - def callback(ctx: click.Context, params: click.Parameter, value: t.Any) -> None: - if not value or ctx.resilient_parsing: - return - - is_windows = sys.platform == "win32" - conda_key = "conda" - - info_dict = { - "bentoml": BENTOML_VERSION, - "python": platform.python_version(), - "platform": platform.platform(), - conda_key: "not installed", - } - - if is_windows: - from ctypes import windll - - # https://stackoverflow.com/a/1026626 - is_admin: bool = windll.shell32.IsUserAnAdmin() != 0 - info_dict["is_window_admin"] = str(is_admin) - else: - info_dict["uid:gid"] = f"{os.geteuid()}:{os.getegid()}" - - if shutil.which("conda"): - try: - # user is currently in a conda environment, - # doing this is faster than invoking `conda --version` - conda_version = get_pkg_version("conda") - except PackageNotFoundError: - # when user is not in a conda environment, there - # is no way to import conda. - conda_version = ( - subprocess.check_output(["conda", "--version"]) - .decode("utf-8") - .strip("\n") - .split(" ")[-1] - ) - info_dict[conda_key] = conda_version - - click.echo("\n".join([f"{k}: {v}" for k, v in info_dict.items()])) - ctx.exit() - - param_decls = ("--env",) - - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", gettext("Print environment info and exit")) - kwargs["callback"] = callback - return click.option(*param_decls, **kwargs) - def create_bentoml_cli(): + from ..context import component_context component_context.component_name = "cli" @@ -94,11 +24,11 @@ def create_bentoml_cli(): @click.group(cls=BentoMLCommandGroup, context_settings=CONTEXT_SETTINGS) @click.version_option(BENTOML_VERSION, "-v", "--version") - @env_option() def cli(): """BentoML CLI""" # Add top-level CLI commands + add_env_command(cli) add_login_command(cli) add_bento_management_commands(cli) add_model_management_commands(cli) diff --git a/bentoml/_internal/cli/bento_management.py b/bentoml/_internal/cli/bento_management.py index 99c51bdcb0d..d22d4022613 100644 --- a/bentoml/_internal/cli/bento_management.py +++ b/bentoml/_internal/cli/bento_management.py @@ -11,12 +11,12 @@ from simple_di import Provide from rich.table import Table from rich.syntax import Syntax -from rich.console import Console from bentoml import Tag from bentoml.bentos import import_bento from bentoml.bentos import build_bentofile +from ..utils import rich_console as console from ..utils import calc_dir_size from ..utils import human_readable_size from ..utils import display_path_under_home @@ -73,7 +73,6 @@ def get(bento_tag: str, output: str) -> None: bentoml get --output=json FraudDetector:20210709_DE14C9 """ bento = bento_store.get(bento_tag) - console = Console() if output == "path": console.print(bento.path) @@ -122,7 +121,7 @@ def list_bentos(bento_name: str, output: str, no_trunc: bool) -> None: bentos, key=lambda x: x.info.creation_time, reverse=True ) ] - console = Console() + if output == "json": info = json.dumps(res, indent=2) console.print(info) diff --git a/bentoml/_internal/cli/env.py b/bentoml/_internal/cli/env.py new file mode 100644 index 00000000000..4441c1da9da --- /dev/null +++ b/bentoml/_internal/cli/env.py @@ -0,0 +1,110 @@ +from __future__ import annotations + +import os +import sys +import typing as t +import platform +import subprocess +from gettext import gettext + +import click + +from bentoml import __version__ as BENTOML_VERSION +from bentoml.exceptions import CLIException + +from ..utils.pkg import get_pkg_version +from ..utils.pkg import PackageNotFoundError + +conda_packages_name = "conda_packages" + + +def run_cmd(cmd: list[str]) -> list[str]: + return subprocess.check_output(cmd).decode("utf-8").split("\n")[:-1] + + +def format_dropdown(title: str, content: t.Iterable[str]) -> str: + processed = "\n".join(content) + return f"""\ +
{title} + +
+ +```{ 'yaml' if title == conda_packages_name else '' } +{processed} +``` + +
+""" + + +def format_keys(key: str, markdown: bool) -> str: + return f"`{key}`" if markdown else key + + +def pretty_format( + info_dict: dict[str, str | list[str]], output: t.Literal["md", "plain"] +) -> str: + out: list[str] = [] + for key, value in info_dict.items(): + if isinstance(value, list): + if output == "md": + out.append(format_dropdown(key, value)) + else: + out.append(f"{key}:\n " + "\n ".join(value)) + else: + out.append(f"{format_keys(key, markdown=output=='md')}: {value}") + return "\n".join(out) + + +def add_env_command(cli: click.Group) -> None: + @cli.command(help=gettext("Print environment info and exit")) + @click.option( + "-o", + "--output", + type=click.Choice(["md", "plain"]), + default="md", + show_default=True, + help="Output format. '-o plain' to display without format.", + ) + @click.pass_context + def env(ctx: click.Context, output: t.Literal["md", "plain"]) -> None: # type: ignore (unused warning) + if output not in ["md", "plain"]: + raise CLIException(f"Unknown output format: {output}") + + is_windows = sys.platform == "win32" + + info_dict: dict[str, str | list[str]] = { + "bentoml": BENTOML_VERSION, + "python": platform.python_version(), + "platform": platform.platform(), + } + + if is_windows: + from ctypes import windll + + # https://stackoverflow.com/a/1026626 + is_admin: bool = windll.shell32.IsUserAnAdmin() != 0 + info_dict["is_window_admin"] = str(is_admin) + else: + info_dict["uid:gid"] = f"{os.geteuid()}:{os.getegid()}" + + if "CONDA_PREFIX" in os.environ: + # conda packages + conda_packages = run_cmd(["conda", "env", "export"]) + + # user is currently in a conda environment, + # doing this is faster than invoking `conda --version` + try: + conda_version = get_pkg_version("conda") + except PackageNotFoundError: + conda_version = run_cmd(["conda", "--version"])[0].split(" ")[-1] + + info_dict["conda"] = conda_version + info_dict["in_conda_env"] = str(True) + info_dict["conda_packages"] = conda_packages + else: + # process info from `pip freeze` + pip_packages = run_cmd(["pip", "freeze"]) + info_dict["pip_packages"] = pip_packages + click.echo(pretty_format(info_dict, output=output)) + ctx.exit(0) diff --git a/bentoml/_internal/cli/model_management.py b/bentoml/_internal/cli/model_management.py index 1254cf1e877..e9bf780f3e0 100644 --- a/bentoml/_internal/cli/model_management.py +++ b/bentoml/_internal/cli/model_management.py @@ -10,14 +10,13 @@ from simple_di import Provide from rich.table import Table from rich.syntax import Syntax -from rich.console import Console from bentoml import Tag from bentoml.models import import_model +from ..utils import rich_console as console from ..utils import calc_dir_size from ..utils import human_readable_size -from ..utils import display_path_under_home from .click_utils import is_valid_bento_tag from .click_utils import BentoMLCommandGroup from .click_utils import is_valid_bento_name @@ -76,7 +75,6 @@ def get(model_tag: str, output: str) -> None: bentoml models get --output=json FraudDetector:20210709_DE14C9 """ model = model_store.get(model_tag) - console = Console() if output == "path": console.print(model.path) @@ -110,7 +108,7 @@ def list_models(model_name: str, output: str, no_trunc: bool) -> None: # show all verions of bento with the name FraudDetector > bentoml models list FraudDetector """ - console = Console() + models = model_store.list(model_name) res = [ { diff --git a/bentoml/_internal/utils/__init__.py b/bentoml/_internal/utils/__init__.py index ff2ff24f1a3..a240d04c9f6 100644 --- a/bentoml/_internal/utils/__init__.py +++ b/bentoml/_internal/utils/__init__.py @@ -19,6 +19,7 @@ import fs import attr import fs.copy +from rich.console import Console if sys.version_info >= (3, 8): from functools import cached_property @@ -43,6 +44,7 @@ T = t.TypeVar("T") _T_co = t.TypeVar("_T_co", covariant=True, bound=t.Any) +rich_console = Console(theme=None) __all__ = [ "bentoml_cattr", @@ -53,6 +55,7 @@ "LazyLoader", "validate_or_create_dir", "display_path_under_home", + "rich_console", ]