| # Copyright 2021-2022 Google LLC | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # https://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # 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. | |
| """ | |
| Invoke tasks | |
| """ | |
| import glob | |
| # ----------------------------------------------------------------------------- | |
| # Imports | |
| # ----------------------------------------------------------------------------- | |
| import os | |
| import shutil | |
| from pathlib import Path | |
| from invoke import Collection, call, task | |
| from invoke.exceptions import Exit, UnexpectedExit | |
| # ----------------------------------------------------------------------------- | |
| ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) | |
| ns = Collection() | |
| # ----------------------------------------------------------------------------- | |
| # Build | |
| # ----------------------------------------------------------------------------- | |
| build_tasks = Collection() | |
| ns.add_collection(build_tasks, name="build") | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def build(ctx, install=False): | |
| if install: | |
| ctx.run('python -m pip install .[build]') | |
| ctx.run("python -m build") | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def release_build(ctx): | |
| build(ctx, install=True) | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def mkdocs(ctx): | |
| ctx.run("mkdocs build -f docs/mkdocs/mkdocs.yml") | |
| # ----------------------------------------------------------------------------- | |
| build_tasks.add_task(build, default=True) | |
| build_tasks.add_task(release_build, name="release") | |
| build_tasks.add_task(mkdocs, name="mkdocs") | |
| # ----------------------------------------------------------------------------- | |
| # Test | |
| # ----------------------------------------------------------------------------- | |
| test_tasks = Collection() | |
| ns.add_collection(test_tasks, name="test") | |
| # ----------------------------------------------------------------------------- | |
| @task(incrementable=["verbose"]) | |
| def test(ctx, match=None, junit=False, install=False, html=False, verbose=0): | |
| # Install the package before running the tests | |
| if install: | |
| ctx.run("python -m pip install .[test]") | |
| args = "" | |
| if junit: | |
| args += "--junit-xml test-results.xml" | |
| if match is not None: | |
| args += f" -k '{match}'" | |
| if html: | |
| args += " --html results.html" | |
| if verbose > 0: | |
| args += f" -{'v' * verbose}" | |
| ctx.run(f"python -m pytest {os.path.join(ROOT_DIR, 'tests')} {args}") | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def release_test(ctx): | |
| test(ctx, install=True) | |
| # ----------------------------------------------------------------------------- | |
| test_tasks.add_task(test, default=True) | |
| test_tasks.add_task(release_test, name="release") | |
| # ----------------------------------------------------------------------------- | |
| # Project | |
| # ----------------------------------------------------------------------------- | |
| project_tasks = Collection() | |
| ns.add_collection(project_tasks, name="project") | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def lint(ctx, disable='C,R', errors_only=False): | |
| options = [] | |
| if disable: | |
| options.append(f"--disable={disable}") | |
| if errors_only: | |
| options.append("-E") | |
| if errors_only: | |
| qualifier = ' (errors only)' | |
| else: | |
| qualifier = f' (disabled: {disable})' if disable else '' | |
| print(f">>> Running the linter{qualifier}...") | |
| try: | |
| print("+++ Checking with ruff...") | |
| ctx.run("ruff check") | |
| print("+++ Checking with pylint...") | |
| ctx.run(f"pylint {' '.join(options)} bumble apps examples tasks.py") | |
| print("The linter is happy. β π π") | |
| except UnexpectedExit as exc: | |
| print("Please check your code against the linter messages. β") | |
| raise Exit(code=1) from exc | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def format_code(ctx, check=False, diff=False): | |
| print(">>> Sorting imports...") | |
| options = [] | |
| try: | |
| if diff: | |
| options.append("--diff") | |
| else: | |
| options.append("--fix") | |
| ctx.run(f"ruff check --select I {' '.join(options)} .") | |
| except UnexpectedExit as exc: | |
| print("Please run 'invoke project.format' or 'isort .' to format the code. β") | |
| raise Exit(code=1) from exc | |
| print(">>> Running the formatter...") | |
| options = [] | |
| if check: | |
| options.append("--check") | |
| if diff: | |
| options.append("--diff") | |
| try: | |
| ctx.run(f"black -S {' '.join(options)} .") | |
| except UnexpectedExit as exc: | |
| print("Please run 'invoke project.format' or 'black .' to format the code. β") | |
| raise Exit(code=1) from exc | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def check_types(ctx): | |
| checklist = ["apps", "bumble", "examples", "tests", "tasks.py"] | |
| try: | |
| ctx.run(f"mypy {' '.join(checklist)}") | |
| except UnexpectedExit as exc: | |
| print("Please check your code against the mypy messages.") | |
| raise Exit(code=1) from exc | |
| # ----------------------------------------------------------------------------- | |
| @task( | |
| pre=[ | |
| call(format_code, check=True), | |
| call(lint, errors_only=True), | |
| call(check_types), | |
| test, | |
| ] | |
| ) | |
| def pre_commit(_ctx): | |
| print("All good!") | |
| # ----------------------------------------------------------------------------- | |
| project_tasks.add_task(lint) | |
| project_tasks.add_task(format_code, name="format") | |
| project_tasks.add_task(check_types, name="check-types") | |
| project_tasks.add_task(pre_commit) | |
| # ----------------------------------------------------------------------------- | |
| # Web | |
| # ----------------------------------------------------------------------------- | |
| web_tasks = Collection() | |
| ns.add_collection(web_tasks, name="web") | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def serve(ctx, port=8000): | |
| """ | |
| Run a simple HTTP server for the examples under the `web` directory. | |
| """ | |
| import http.server | |
| address = ("", port) | |
| class Handler(http.server.SimpleHTTPRequestHandler): | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, directory="web", **kwargs) | |
| server = http.server.HTTPServer(address, Handler) | |
| print(f"Now serving on port {port} πΈοΈ") | |
| server.serve_forever() | |
| # ----------------------------------------------------------------------------- | |
| @task | |
| def web_build(ctx): | |
| # Step 1: build the wheel | |
| build(ctx) | |
| # Step 2: Copy the wheel to the web folder, so the http server can access it | |
| newest_wheel = Path(max(glob.glob('dist/*.whl'), key=lambda f: os.path.getmtime(f))) | |
| shutil.copy(newest_wheel, Path('web/')) | |
| # Step 3: Write wheel's name to web/packageFile | |
| with open(Path('web', 'packageFile'), mode='w') as package_file: | |
| package_file.write(str(Path('/') / newest_wheel.name)) | |
| # Step 4: Success! | |
| print('Include ?packageFile=true in your URL!') | |
| # ----------------------------------------------------------------------------- | |
| web_tasks.add_task(serve) | |
| web_tasks.add_task(web_build, name="build") |