tasks.py (122 lines of code) (raw):
# Copyright 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
#
# http://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.
"""Module for defining maintainence tasks."""
import sys
import yaml
from invoke import task # type: ignore
with open(".github/workflows/linter.yaml", encoding="utf-8") as file:
_LINTER_ACTIONS_CONFIG = yaml.safe_load(file)
_LINTER_ENV = _LINTER_ACTIONS_CONFIG["jobs"]["build"]["steps"][4]["env"]
_SUPER_LINTER_VERSION = "ghcr.io/github/super-linter:slim-v4.9.7"
_LINTER_PATTERN = (
"sudo docker run "
"--workdir /github/workspace "
"--rm "
'-e "{validate}" '
'-e "{config}" '
'-e "RUN_LOCAL=true" '
'-e PYTHONPATH="/tmp/lint/venv/lib/python3.10/site-packages" '
f'-e "FILTER_REGEX_EXCLUDE={_LINTER_ENV["FILTER_REGEX_EXCLUDE"]}" '
f'-e "LINTER_RULES_PATH=." '
f'-e YAML_ERROR_ON_WARNING={_LINTER_ENV["YAML_ERROR_ON_WARNING"]} '
f"-v $(pwd):/tmp/lint {_SUPER_LINTER_VERSION}"
)
_TERRASCAN_CONFIG = "TERRAFORM_TERRASCAN_CONFIG_FILE"
_LINTER_CONFIG = {
"terraform": {
"validate": "VALIDATE_TERRAFORM_TFLINT=true",
"config": f'TERRAFORM_TFLINT_CONFIG_FILE={_LINTER_ENV["TERRAFORM_TFLINT_CONFIG_FILE"]}',
},
"javascript": {
"validate": "VALIDATE_JAVASCRIPT_ES=true",
"config": f'JAVASCRIPT_ES_CONFIG_FILE={_LINTER_ENV["JAVASCRIPT_ES_CONFIG_FILE"]}',
},
"black": {
"validate": "VALIDATE_PYTHON_BLACK=true",
"config": f'PYTHON_BLACK_CONFIG_FILE={_LINTER_ENV["PYTHON_BLACK_CONFIG_FILE"]}',
},
"isort": {
"validate": "VALIDATE_PYTHON_ISORT=true",
"config": f'PYTHON_ISORT_CONFIG_FILE={_LINTER_ENV["PYTHON_ISORT_CONFIG_FILE"]}',
},
"jscpd": {
"validate": "VALIDATE_JSCPD=true",
"config": f'JSCPD_CONFIG_FILE={_LINTER_ENV["JSCPD_CONFIG_FILE"]}',
},
"flake8": {
"validate": "VALIDATE_PYTHON_FLAKE8=true",
"config": f'PYTHON_FLAKE8_CONFIG_FILE={_LINTER_ENV["PYTHON_FLAKE8_CONFIG_FILE"]}',
},
"pylint": {
"validate": "VALIDATE_PYTHON_PYLINT=true",
"config": f'PYTHON_PYLINT_CONFIG_FILE={_LINTER_ENV["PYTHON_PYLINT_CONFIG_FILE"]}',
},
"mypy": {
"validate": "VALIDATE_PYTHON_MYPY=true",
"config": f'PYTHON_MYPY_CONFIG_FILE={_LINTER_ENV["PYTHON_MYPY_CONFIG_FILE"]}',
},
"bash": {
"validate": "VALIDATE_BASH=true",
"config": "BASH_CONFIG_FILE=None",
},
"hadolint": {
"validate": "VALIDATE_DOCKERFILE_HADOLINT=true",
"config": f'DOCKERFILE_HADOLINT_FILE_NAME={_LINTER_ENV["DOCKERFILE_HADOLINT_FILE_NAME"]}',
},
"markdown": {
"validate": "VALIDATE_MARKDOWN=true",
"config": f'MARKDOWN_CONFIG_FILE={_LINTER_ENV["MARKDOWN_CONFIG_FILE"]}',
},
"textlint": {
"validate": "VALIDATE_NATURAL_LANGUAGE=true",
"config": f'NATURAL_LANGUAGE_CONFIG_FILE={_LINTER_ENV["NATURAL_LANGUAGE_CONFIG_FILE"]}',
},
"yaml": {
"validate": "VALIDATE_YAML=true",
"config": f'YAML_CONFIG_FILE={_LINTER_ENV["YAML_CONFIG_FILE"]}',
},
"terrascan": {
"validate": "VALIDATE_TERRAFORM_TERRASCAN=true",
"config": f"TERRAFORM_TERRASCAN_CONFIG_FILE={_LINTER_ENV[_TERRASCAN_CONFIG]}",
},
"stylelint": {
"validate": "VALIDATE_CSS=true",
"config": f'CSS_FILE_NAME={_LINTER_ENV["CSS_FILE_NAME"]}',
},
}
def print_result(linter, result, hide):
"""Print result of linter run with pyinvoke."""
if result.exited:
print(f'linter "{linter}": FAILURE (code {result.exited})')
print(result.stderr.strip())
else:
if not hide:
print(f'linter "{linter}": OK')
@task
def autofix(ctx):
"""Run black and isort before linting."""
ctx.run("isort --skip=noxfile.py --skip=venv .", warn=False, hide=False)
ctx.run("black --exclude=venv .", warn=False, hide=False)
@task
def lint(ctx, linter="all", warn=False, hide=False, run_autofix=True):
"""Run a linter(s) using pyinvoke."""
if linter == "all":
if run_autofix:
autofix(ctx)
any_failure = False
for curr_linter in _LINTER_CONFIG:
result = lint(ctx, curr_linter, warn=True, hide=True, run_autofix=False)
print_result(curr_linter, result, hide)
if result.exited:
any_failure = result.exited
if (not warn) and any_failure:
sys.exit(result.exited)
return result
if run_autofix:
autofix(ctx)
result = ctx.run(
_LINTER_PATTERN.format(
validate=_LINTER_CONFIG[linter]["validate"],
config=_LINTER_CONFIG[linter]["config"],
),
warn=True,
hide=True,
)
print_result(linter, result, hide)
if (not warn) and result.exited:
sys.exit(result.exited)
return result