From 14d7cecc5545cdef1fbbd12ef0a0300a93f4c6a2 Mon Sep 17 00:00:00 2001 From: Luke Tainton Date: Sun, 4 Aug 2024 19:02:10 +0100 Subject: [PATCH] chore: add pre-commit --- .coveragerc | 2 +- .github/CODEOWNERS | 2 +- .github/renovate.json | 40 +++++++++++++++++++-------- .pre-commit-config.yaml | 60 ++++++++++++++++++++++++++++++++++++++++ app/config.py | 1 + app/img.py | 5 ++-- app/main.py | 4 +-- app/meme.py | 12 ++++---- requirements-dev.txt | 1 - sonar-project.properties | 2 +- tests/test_config.py | 5 ++-- tests/test_meme.py | 4 +-- 12 files changed, 107 insertions(+), 31 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.coveragerc b/.coveragerc index fa2ee67..cab8101 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,3 @@ [coverage:run] relative_files = True -branch = True \ No newline at end of file +branch = True diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0d35f6e..55e6153 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @luketainton \ No newline at end of file +* @luketainton diff --git a/.github/renovate.json b/.github/renovate.json index e2cb0cc..2cdc1a3 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,26 +1,42 @@ { - "extends": ["config:base"], - "platformCommit": true, - "dependencyDashboardAutoclose": true, "assignAutomerge": true, "assigneesFromCodeOwners": true, - "rebaseWhen": "behind-base-branch", - "rollbackPrs": true, - "labels": ["dependencies"], + "dependencyDashboardAutoclose": true, + "extends": [ + "config:base" + ], + "labels": [ + "dependencies" + ], "packageRules": [ { - "matchPackagePatterns": ["black", "pylint"], - "labels": ["linting"] + "labels": [ + "linting" + ], + "matchPackagePatterns": [ + "black", + "pylint" + ] }, { - "matchPackagePatterns": ["coverage", "pytest"], - "labels": ["unit-tests"] + "labels": [ + "unit-tests" + ], + "matchPackagePatterns": [ + "coverage", + "pytest" + ] } ], + "platformCommit": true, + "rebaseWhen": "behind-base-branch", + "rollbackPrs": true, "vulnerabilityAlerts": { - "enabled": true, - "labels": ["security"], "commitMessagePrefix": "[SECURITY] ", + "enabled": true, + "labels": [ + "security" + ], "prCreation": "immediate" } } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4d8ce61 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,60 @@ +fail_fast: false + +minimum_pre_commit_version: 3.8.0 + +default_install_hook_types: [pre-commit, commit-msg] + +default_language_version: + python: python3.11 + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: trailing-whitespace + - id: mixed-line-ending + - id: end-of-file-fixer + - id: requirements-txt-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-ast + - id: check-docstring-first + - id: check-json + - id: check-merge-conflict + - id: check-toml + - id: check-xml + - id: detect-private-key + - id: no-commit-to-branch + - id: requirements-txt-fixer + - id: name-tests-test + args: [--pytest-test-first] + - id: pretty-format-json + args: [--autofix] + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.5.6 + hooks: + - id: ruff-format # Run the formatter. + - id: ruff # Run the linter. + args: [--fix] + + # - repo: https://github.com/pycqa/isort + # rev: 5.13.2 + # hooks: + # - id: isort + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: python-use-type-annotations + + - repo: https://github.com/asottile/pyupgrade + rev: v3.17.0 + hooks: + - id: pyupgrade + + - repo: https://github.com/compilerla/conventional-pre-commit + rev: v3.4.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] diff --git a/app/config.py b/app/config.py index 0c4d476..f2a75e3 100644 --- a/app/config.py +++ b/app/config.py @@ -5,6 +5,7 @@ import os class Config: """Configuration module.""" + def __init__(self) -> None: """Configuration module.""" self.__environment: str = os.environ.get("APP_LIFECYCLE", "DEV").upper() diff --git a/app/img.py b/app/img.py index 312b8e3..b59d8c5 100644 --- a/app/img.py +++ b/app/img.py @@ -1,6 +1,5 @@ import requests - CHAR_REPLACEMENTS: list = [ ["_", "__"], ["-", "--"], @@ -56,5 +55,7 @@ def generate_api_url(template: str, top_str: str, btm_str: str) -> str: top_str = format_meme_string(top_str) btm_str = format_meme_string(btm_str) - url: str = f"https://api.memegen.link/images/{tmpl_name}/{top_str}/{btm_str}.{tmpl_ext}" + url: str = ( + f"https://api.memegen.link/images/{tmpl_name}/{top_str}/{btm_str}.{tmpl_ext}" + ) return url diff --git a/app/main.py b/app/main.py index feb74dc..4e28ad4 100644 --- a/app/main.py +++ b/app/main.py @@ -2,13 +2,11 @@ import sentry_sdk from sentry_sdk.integrations.stdlib import StdlibIntegration - from webex_bot.webex_bot import WebexBot from app import close, meme from app.config import config - if config.sentry_enabled: apm = sentry_sdk.init( dsn=config.sentry_dsn, @@ -16,7 +14,7 @@ if config.sentry_enabled: environment=config.environment, release=config.version, integrations=[StdlibIntegration()], - spotlight=True + spotlight=True, ) diff --git a/app/meme.py b/app/meme.py index fe57a77..dc25e31 100644 --- a/app/meme.py +++ b/app/meme.py @@ -2,25 +2,25 @@ from webex_bot.models.command import Command from webex_bot.models.response import Response, response_from_adaptive_card from webexteamssdk.models.cards import ( AdaptiveCard, + Choice, + Choices, Column, ColumnSet, FontSize, FontWeight, Text, TextBlock, - Choice, - Choices, ) -from webexteamssdk.models.cards.actions import Submit, OpenUrl +from webexteamssdk.models.cards.actions import OpenUrl, Submit from app import img - TEMPLATES = img.get_templates() class MakeMemeCommand(Command): """Class for initial Webex interactive card.""" + def __init__(self) -> None: super().__init__( command_keyword="/meme", @@ -69,7 +69,8 @@ class MakeMemeCommand(Command): id="meme_type", isMultiSelect=False, choices=[ - Choice(title=x["name"], value=x["choiceval"]) for x in TEMPLATES + Choice(title=x["name"], value=x["choiceval"]) + for x in TEMPLATES ], ), Text(id="text_top", placeholder="Top Text", maxLength=100), @@ -100,6 +101,7 @@ class MakeMemeCommand(Command): class MakeMemeCallback(Command): """Class to process user data and return meme.""" + def __init__(self) -> None: super().__init__( card_callback_keyword="make_meme_callback_rbamzfyx", diff --git a/requirements-dev.txt b/requirements-dev.txt index 753c6ff..b5db43e 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -19,7 +19,6 @@ pathspec==0.12.1 platformdirs==4.2.2 pluggy==1.5.0 pre-commit==3.8.0 -pylint-exit==1.2.0 pylint==3.2.6 pylint-exit==1.2.0 pytest==8.3.2 diff --git a/sonar-project.properties b/sonar-project.properties index 0775bb9..08f2552 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -8,4 +8,4 @@ sonar.python.pylint.reportPaths=lintreport.txt sonar.python.xunit.reportPath=testresults.xml sonar.sources=app sonar.tests=tests -sonar.exclusions=,.github/**,.gitignore,CODEOWNERS,CHANGELOG.md,LICENSE.md,README.md,renovate.json,requirements-dev.txt,requirements.txt \ No newline at end of file +sonar.exclusions=,.github/**,.gitignore,CODEOWNERS,CHANGELOG.md,LICENSE.md,README.md,renovate.json,requirements-dev.txt,requirements.txt diff --git a/tests/test_config.py b/tests/test_config.py index e389636..c90373e 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,12 +2,11 @@ import os - vars: dict = { "APP_VERSION": "dev", "WEBEX_API_KEY": "testing", "SENTRY_ENABLED": "false", - "SENTRY_DSN": "http://localhost" + "SENTRY_DSN": "http://localhost", } @@ -15,7 +14,7 @@ for var, value in vars.items(): os.environ[var] = value # needs to be imported AFTER environment variables are set -from app.config import config # pragma: no cover +from app.config import config # pragma: no cover # noqa: E402 def test_config() -> None: diff --git a/tests/test_meme.py b/tests/test_meme.py index 20479f2..3c0a878 100644 --- a/tests/test_meme.py +++ b/tests/test_meme.py @@ -30,7 +30,7 @@ def test_error_false() -> None: callback.text_bottom = "TEST" result: Response = callback.execute(None, None, {"target": {"globalId": "TEST"}}) assert ( - isinstance(result, Response) \ - and result.roomId == "TEST" \ + isinstance(result, Response) + and result.roomId == "TEST" and result.files[0] == callback.meme_filename )