• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021-2022 Google LLC
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#      https://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"""
16Invoke tasks
17"""
18
19# -----------------------------------------------------------------------------
20# Imports
21# -----------------------------------------------------------------------------
22import os
23
24from invoke import task, call, Collection
25from invoke.exceptions import Exit, UnexpectedExit
26
27
28# -----------------------------------------------------------------------------
29ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
30
31ns = Collection()
32
33
34# -----------------------------------------------------------------------------
35# Build
36# -----------------------------------------------------------------------------
37build_tasks = Collection()
38ns.add_collection(build_tasks, name="build")
39
40
41# -----------------------------------------------------------------------------
42@task
43def build(ctx, install=False):
44    if install:
45        ctx.run('python -m pip install .[build]')
46
47    ctx.run("python -m build")
48
49
50# -----------------------------------------------------------------------------
51@task
52def release_build(ctx):
53    build(ctx, install=True)
54
55
56# -----------------------------------------------------------------------------
57@task
58def mkdocs(ctx):
59    ctx.run("mkdocs build -f docs/mkdocs/mkdocs.yml")
60
61
62# -----------------------------------------------------------------------------
63build_tasks.add_task(build, default=True)
64build_tasks.add_task(release_build, name="release")
65build_tasks.add_task(mkdocs, name="mkdocs")
66
67
68# -----------------------------------------------------------------------------
69# Test
70# -----------------------------------------------------------------------------
71test_tasks = Collection()
72ns.add_collection(test_tasks, name="test")
73
74
75# -----------------------------------------------------------------------------
76@task(incrementable=["verbose"])
77def test(ctx, match=None, junit=False, install=False, html=False, verbose=0):
78    # Install the package before running the tests
79    if install:
80        ctx.run("python -m pip install .[test]")
81
82    args = ""
83    if junit:
84        args += "--junit-xml test-results.xml"
85    if match is not None:
86        args += f" -k '{match}'"
87    if html:
88        args += " --html results.html"
89    if verbose > 0:
90        args += f" -{'v' * verbose}"
91    ctx.run(f"python -m pytest {os.path.join(ROOT_DIR, 'tests')} {args}")
92
93
94# -----------------------------------------------------------------------------
95@task
96def release_test(ctx):
97    test(ctx, install=True)
98
99
100# -----------------------------------------------------------------------------
101test_tasks.add_task(test, default=True)
102test_tasks.add_task(release_test, name="release")
103
104# -----------------------------------------------------------------------------
105# Project
106# -----------------------------------------------------------------------------
107project_tasks = Collection()
108ns.add_collection(project_tasks, name="project")
109
110
111# -----------------------------------------------------------------------------
112@task
113def lint(ctx, disable='C,R', errors_only=False):
114    options = []
115    if disable:
116        options.append(f"--disable={disable}")
117    if errors_only:
118        options.append("-E")
119
120    if errors_only:
121        qualifier = ' (errors only)'
122    else:
123        qualifier = f' (disabled: {disable})' if disable else ''
124
125    print(f">>> Running the linter{qualifier}...")
126    try:
127        ctx.run(f"pylint {' '.join(options)} bumble apps examples tasks.py")
128        print("The linter is happy. ✅ �� ��'")
129    except UnexpectedExit as exc:
130        print("Please check your code against the linter messages. ❌")
131        raise Exit(code=1) from exc
132
133
134# -----------------------------------------------------------------------------
135@task
136def format_code(ctx, check=False, diff=False):
137    options = []
138    if check:
139        options.append("--check")
140    if diff:
141        options.append("--diff")
142
143    print(">>> Running the formatter...")
144    try:
145        ctx.run(f"black -S {' '.join(options)} .")
146    except UnexpectedExit as exc:
147        print("Please run 'invoke project.format' or 'black .' to format the code. ❌")
148        raise Exit(code=1) from exc
149
150
151# -----------------------------------------------------------------------------
152@task
153def check_types(ctx):
154    checklist = ["apps", "bumble", "examples", "tests", "tasks.py"]
155    try:
156        ctx.run(f"mypy {' '.join(checklist)}")
157    except UnexpectedExit as exc:
158        print("Please check your code against the mypy messages.")
159        raise Exit(code=1) from exc
160
161
162# -----------------------------------------------------------------------------
163@task(
164    pre=[
165        call(format_code, check=True),
166        call(lint, errors_only=True),
167        call(check_types),
168        test,
169    ]
170)
171def pre_commit(_ctx):
172    print("All good!")
173
174
175# -----------------------------------------------------------------------------
176project_tasks.add_task(lint)
177project_tasks.add_task(format_code, name="format")
178project_tasks.add_task(check_types, name="check-types")
179project_tasks.add_task(pre_commit)
180