Skip to content

Commit 099facf

Browse files
authored
Use pre-commit + black (#103)
1 parent 511c240 commit 099facf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2526
-2389
lines changed

.flake8

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[flake8]
2+
ignore = E203,W503
3+
max-line-length = 159
4+
exclude = .git,__pycache__

.isort.cfg

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[settings]
2+
known_first_party = code_coverage_backend,code_coverage_bot,code_coverage_tools,conftest
3+
known_third_party = connexion,datadog,dateutil,fakeredis,flask,flask_cors,flask_talisman,google,hglib,jsone,jsonschema,libmozdata,logbook,pytest,pytz,redis,requests,responses,setuptools,structlog,taskcluster,werkzeug,zstandard
4+
force_single_line = True
5+
default_section=FIRSTPARTY
6+
line_length=159

.pre-commit-config.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
repos:
2+
- repo: https://github.com/asottile/seed-isort-config
3+
rev: v1.9.2
4+
hooks:
5+
- id: seed-isort-config
6+
- repo: https://github.com/pre-commit/mirrors-isort
7+
rev: v4.3.21
8+
hooks:
9+
- id: isort
10+
- repo: https://github.com/ambv/black
11+
rev: stable
12+
hooks:
13+
- id: black
14+
- repo: https://gitlab.com/pycqa/flake8
15+
rev: 3.7.8
16+
hooks:
17+
- id: flake8
18+
additional_dependencies:
19+
- 'flake8-coding==1.3.1'
20+
- 'flake8-copyright==0.2.2'
21+
- 'flake8-debugger==3.1.0'
22+
- 'flake8-mypy==17.8.0'
23+
- repo: https://github.com/pre-commit/pre-commit-hooks
24+
rev: v2.2.3
25+
hooks:
26+
- id: trailing-whitespace
27+
- id: check-yaml
28+
- id: mixed-line-ending
29+
- id: name-tests-test
30+
args: ['--django']
31+
- id: check-json
32+
- repo: https://github.com/codespell-project/codespell
33+
rev: v1.15.0
34+
hooks:
35+
- id: codespell
36+
args: ['--exclude-file=bot/tests/fixtures/activedata_chunk_to_tests.json']
37+
- repo: https://github.com/marco-c/taskcluster_yml_validator
38+
rev: v0.0.2
39+
hooks:
40+
- id: taskcluster_yml
41+
- repo: meta
42+
hooks:
43+
- id: check-useless-excludes
44+
45+
default_language_version:
46+
python: python3.7

.taskcluster.yml

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ tasks:
4343

4444
taskboot_image: "mozilla/taskboot:0.1.9"
4545
in:
46-
- taskId: {$eval: as_slugid("bot_check_lint")}
46+
- taskId: {$eval: as_slugid("check_lint")}
4747
provisionerId: aws-provisioner-v1
4848
workerType: github-worker
4949
created: {$fromNow: ''}
@@ -57,31 +57,11 @@ tasks:
5757
- "git clone --quiet ${repository} /src && cd /src && git checkout ${head_rev} -b checks &&
5858
cd /src/tools && python setup.py install &&
5959
cd /src/bot && pip install --quiet . && pip install --quiet -r requirements-dev.txt &&
60-
flake8"
61-
metadata:
62-
name: "Code Coverage Bot checks: linting"
63-
description: Check python code style with flake8
64-
65-
source: https://github.com/mozilla/code-coverage
66-
67-
- taskId: {$eval: as_slugid("backend_check_lint")}
68-
provisionerId: aws-provisioner-v1
69-
workerType: github-worker
70-
created: {$fromNow: ''}
71-
deadline: {$fromNow: '1 hour'}
72-
payload:
73-
maxRunTime: 3600
74-
image: python:3
75-
command:
76-
- sh
77-
- -lxce
78-
- "git clone --quiet ${repository} /src && cd /src && git checkout ${head_rev} -b checks &&
79-
cd /src/tools && python setup.py install &&
8060
cd /src/backend && pip install --quiet . && pip install --quiet -r requirements-dev.txt &&
81-
flake8"
61+
cd /src && pre-commit run -a"
8262
metadata:
83-
name: "Code Coverage Backend checks: linting"
84-
description: Check python code style with flake8
63+
name: "Code Coverage checks: linting"
64+
description: Check code style with pre-commit hooks
8565
8666
source: https://github.com/mozilla/code-coverage
8767

@@ -134,7 +114,7 @@ tasks:
134114
provisionerId: aws-provisioner-v1
135115
workerType: releng-svc
136116
dependencies:
137-
- {$eval: as_slugid("backend_check_lint")}
117+
- {$eval: as_slugid("check_lint")}
138118
- {$eval: as_slugid("backend_check_tests")}
139119
payload:
140120
capabilities:
@@ -175,7 +155,7 @@ tasks:
175155
provisionerId: aws-provisioner-v1
176156
workerType: releng-svc
177157
dependencies:
178-
- {$eval: as_slugid("bot_check_lint")}
158+
- {$eval: as_slugid("check_lint")}
179159
- {$eval: as_slugid("bot_check_tests")}
180160
payload:
181161
capabilities:

backend/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,19 @@ We currently have several endpoints implemented:
1212
* `/v2/path` provides the code coverage information for a directory or file in a repository, at a given revision.
1313

1414

15-
## Setup instructions for developpers
15+
## Setup instructions for developers
1616

1717
```shell
1818
mkvirtualenv -p /usr/bin/python3 ccov-backend
1919
cd backend/
20-
pip install -r requirements.txt -r requirements-dev.txt
20+
pip install -r requirements.txt -r requirements-dev.txt
2121
pip install -e .
2222
```
2323

2424
You should now be able to run tests and linting:
2525

2626
```shell
27-
pytest
28-
flake8
27+
pre-commit run -a
2928
```
3029

3130
## Run a redis instance through docker

backend/code_coverage_backend/api.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,46 @@
99
from code_coverage_backend.config import COVERAGE_EXTENSIONS
1010
from code_coverage_backend.gcp import load_cache
1111

12-
DEFAULT_REPOSITORY = 'mozilla-central'
12+
DEFAULT_REPOSITORY = "mozilla-central"
1313
logger = structlog.get_logger(__name__)
1414

1515

1616
def coverage_supported_extensions():
17-
'''
17+
"""
1818
List all the file extensions we currently support
19-
'''
19+
"""
2020
return COVERAGE_EXTENSIONS
2121

2222

2323
def coverage_latest(repository=DEFAULT_REPOSITORY):
24-
'''
24+
"""
2525
List the last 10 reports available on the server
26-
'''
26+
"""
2727
gcp = load_cache()
2828
if gcp is None:
29-
logger.error('No GCP cache available')
29+
logger.error("No GCP cache available")
3030
abort(500)
3131

3232
try:
3333
return [
34-
{
35-
'revision': revision,
36-
'push': push_id,
37-
}
34+
{"revision": revision, "push": push_id}
3835
for revision, push_id in gcp.list_reports(repository, 10)
3936
]
4037
except Exception as e:
41-
logger.warn('Failed to retrieve latest reports: {}'.format(e))
38+
logger.warn("Failed to retrieve latest reports: {}".format(e))
4239
abort(404)
4340

4441

45-
def coverage_for_path(path='', changeset=None, repository=DEFAULT_REPOSITORY):
46-
'''
42+
def coverage_for_path(path="", changeset=None, repository=DEFAULT_REPOSITORY):
43+
"""
4744
Aggregate coverage for a path, regardless of its type:
4845
* file, gives its coverage percent
4946
* directory, gives coverage percent for its direct sub elements
5047
files and folders (recursive average)
51-
'''
48+
"""
5249
gcp = load_cache()
5350
if gcp is None:
54-
logger.error('No GCP cache available')
51+
logger.error("No GCP cache available")
5552
abort(500)
5653

5754
try:
@@ -62,28 +59,41 @@ def coverage_for_path(path='', changeset=None, repository=DEFAULT_REPOSITORY):
6259
# Fallback to latest report
6360
changeset, _ = gcp.find_report(repository)
6461
except Exception as e:
65-
logger.warn('Failed to retrieve report: {}'.format(e))
62+
logger.warn("Failed to retrieve report: {}".format(e))
6663
abort(404)
6764

6865
# Load tests data from GCP
6966
try:
7067
return gcp.get_coverage(repository, changeset, path)
7168
except Exception as e:
72-
logger.warn('Failed to load coverage', repo=repository, changeset=changeset, path=path, error=str(e))
69+
logger.warn(
70+
"Failed to load coverage",
71+
repo=repository,
72+
changeset=changeset,
73+
path=path,
74+
error=str(e),
75+
)
7376
abort(400)
7477

7578

76-
def coverage_history(repository=DEFAULT_REPOSITORY, path='', start=None, end=None):
77-
'''
79+
def coverage_history(repository=DEFAULT_REPOSITORY, path="", start=None, end=None):
80+
"""
7881
List overall coverage from ingested reports over a period of time
79-
'''
82+
"""
8083
gcp = load_cache()
8184
if gcp is None:
82-
logger.error('No GCP cache available')
85+
logger.error("No GCP cache available")
8386
abort(500)
8487

8588
try:
8689
return gcp.get_history(repository, path=path, start=start, end=end)
8790
except Exception as e:
88-
logger.warn('Failed to load history', repo=repository, path=path, start=start, end=end, error=str(e))
91+
logger.warn(
92+
"Failed to load history",
93+
repo=repository,
94+
path=path,
95+
start=start,
96+
end=end,
97+
error=str(e),
98+
)
8999
abort(400)

backend/code_coverage_backend/backend/__init__.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,25 @@ def create_app():
1919
# Load secrets from Taskcluster
2020
taskcluster.auth()
2121
taskcluster.load_secrets(
22-
os.environ.get('TASKCLUSTER_SECRET'),
22+
os.environ.get("TASKCLUSTER_SECRET"),
2323
code_coverage_backend.config.PROJECT_NAME,
24-
required=['GOOGLE_CLOUD_STORAGE', 'APP_CHANNEL'],
25-
existing={
26-
'REDIS_URL': os.environ.get('REDIS_URL', 'redis://localhost:6379')
27-
}
24+
required=["GOOGLE_CLOUD_STORAGE", "APP_CHANNEL"],
25+
existing={"REDIS_URL": os.environ.get("REDIS_URL", "redis://localhost:6379")},
2826
)
2927

3028
# Configure logger
3129
init_logger(
3230
code_coverage_backend.config.PROJECT_NAME,
33-
PAPERTRAIL_HOST=taskcluster.secrets.get('PAPERTRAIL_HOST'),
34-
PAPERTRAIL_PORT=taskcluster.secrets.get('PAPERTRAIL_PORT'),
35-
SENTRY_DSN=taskcluster.secrets.get('SENTRY_DSN'),
31+
PAPERTRAIL_HOST=taskcluster.secrets.get("PAPERTRAIL_HOST"),
32+
PAPERTRAIL_PORT=taskcluster.secrets.get("PAPERTRAIL_PORT"),
33+
SENTRY_DSN=taskcluster.secrets.get("SENTRY_DSN"),
3634
)
3735
logger = structlog.get_logger(__name__)
3836

3937
app = build_flask_app(
4038
project_name=code_coverage_backend.config.PROJECT_NAME,
4139
app_name=code_coverage_backend.config.APP_NAME,
42-
openapi=os.path.join(os.path.dirname(__file__), '../api.yml')
40+
openapi=os.path.join(os.path.dirname(__file__), "../api.yml"),
4341
)
4442

4543
# Setup datadog stats
@@ -49,6 +47,6 @@ def create_app():
4947
try:
5048
code_coverage_backend.gcp.load_cache()
5149
except Exception as e:
52-
logger.warn('GCP cache warmup failed: {}'.format(e))
50+
logger.warn("GCP cache warmup failed: {}".format(e))
5351

5452
return app

backend/code_coverage_backend/backend/build.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
TALISMAN_CONFIG = dict(
2626
# on heroku force https redirect
27-
force_https='DYNO' in os.environ,
27+
force_https="DYNO" in os.environ,
2828
force_https_permanent=False,
2929
force_file_save=False,
3030
frame_options=flask_talisman.talisman.SAMEORIGIN,
@@ -34,12 +34,12 @@
3434
strict_transport_security_max_age=flask_talisman.talisman.ONE_YEAR_IN_SECS,
3535
strict_transport_security_include_subdomains=True,
3636
content_security_policy={
37-
'default-src': '\'none\'',
37+
"default-src": "'none'",
3838
# unsafe-inline is needed for the Swagger UI
39-
'script-src': '\'self\' \'unsafe-inline\'',
40-
'style-src': '\'self\' \'unsafe-inline\'',
41-
'img-src': '\'self\'',
42-
'connect-src': '\'self\'',
39+
"script-src": "'self' 'unsafe-inline'",
40+
"style-src": "'self' 'unsafe-inline'",
41+
"img-src": "'self'",
42+
"connect-src": "'self'",
4343
},
4444
content_security_policy_report_uri=None,
4545
content_security_policy_report_only=False,
@@ -50,23 +50,23 @@
5050

5151
def handle_default_exceptions(e):
5252
error = {
53-
'type': 'about:blank',
54-
'title': str(e),
55-
'status': getattr(e, 'code', 500),
56-
'detail': getattr(e, 'description', str(e)),
57-
'instance': 'about:blank',
53+
"type": "about:blank",
54+
"title": str(e),
55+
"status": getattr(e, "code", 500),
56+
"detail": getattr(e, "description", str(e)),
57+
"instance": "about:blank",
5858
}
59-
return flask.jsonify(error), error['status']
59+
return flask.jsonify(error), error["status"]
6060

6161

6262
def build_flask_app(project_name, app_name, openapi):
63-
'''
63+
"""
6464
Create a new Flask backend application
6565
app_name is the Python application name, used as Flask import_name
6666
project_name is a "nice" name, used to identify the application
67-
'''
68-
assert os.path.exists(openapi), 'Missing openapi file {}'.format(openapi)
69-
logger.debug('Initializing', app=app_name, openapi=openapi)
67+
"""
68+
assert os.path.exists(openapi), "Missing openapi file {}".format(openapi)
69+
logger.debug("Initializing", app=app_name, openapi=openapi)
7070

7171
# Start OpenAPI app
7272
app = connexion.App(import_name=app_name)
@@ -79,19 +79,21 @@ def build_flask_app(project_name, app_name, openapi):
7979

8080
# Enable wildcard CORS
8181
cors = flask_cors.CORS()
82-
cors.init_app(app.app, origins=['*'])
82+
cors.init_app(app.app, origins=["*"])
8383

8484
# Add exception Json renderer
8585
for code, exception in werkzeug.exceptions.default_exceptions.items():
8686
app.app.register_error_handler(exception, handle_default_exceptions)
8787

8888
# Redirect root to API
89-
app.add_url_rule('/', 'root', lambda: flask.redirect(app.options.openapi_console_ui_path))
89+
app.add_url_rule(
90+
"/", "root", lambda: flask.redirect(app.options.openapi_console_ui_path)
91+
)
9092

9193
# Dockerflow checks
92-
app.add_url_rule('/__heartbeat__', view_func=heartbeat_response)
93-
app.add_url_rule('/__lbheartbeat__', view_func=lbheartbeat_response)
94-
app.add_url_rule('/__version__', view_func=get_version)
94+
app.add_url_rule("/__heartbeat__", view_func=heartbeat_response)
95+
app.add_url_rule("/__lbheartbeat__", view_func=lbheartbeat_response)
96+
app.add_url_rule("/__version__", view_func=get_version)
9597

96-
logger.debug('Initialized', app=app.name)
98+
logger.debug("Initialized", app=app.name)
9799
return app

0 commit comments

Comments
 (0)