Skip to content

Commit

Permalink
Merge pull request #26 from niklasstoffers/lint-workflow
Browse files Browse the repository at this point in the history
Add linting, lint workflow and fix linter errors
  • Loading branch information
mergify[bot] authored Dec 26, 2023
2 parents d74a988 + 6672819 commit 7c50059
Show file tree
Hide file tree
Showing 56 changed files with 227 additions and 93 deletions.
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
exclude = __pycache__,.pytest_cache,.venv,venv
max-complexity = 10
max_line_length = 250
20 changes: 20 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: LINT

on: [push]

jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Wait for build
uses: lewagon/[email protected]
with:
ref: ${{ github.ref }}
check-name: 'build'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 5
- name: Run lint
run: |
./ci_lint.sh
7 changes: 7 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ jobs:
check-name: 'test'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 5
- name: Wait for lint
uses: lewagon/[email protected]
with:
ref: ${{ github.ref }}
check-name: 'lint'
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 5
- name: Download build artifacts
uses: dawidd6/action-download-artifact@v3
with:
Expand Down
8 changes: 7 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ repos:
hooks:
- id: ggshield
language_version: python3
stages: [commit]
stages: [commit]
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
files: .
args: [--config, .flake8]
2 changes: 1 addition & 1 deletion autoapprove/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
app.include_router(comment_router)

logger: Logger = getLogger(__name__)
logger.info("Application startup complete")
logger.info("Application startup complete")
6 changes: 3 additions & 3 deletions autoapprove/app_info.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
VERSION="0.1.0"
NAME="Gitlab Auto Approve"
SUMMARY="Gitlab webhook for automatically approving merge requests."
VERSION = "0.1.0"
NAME = "Gitlab Auto Approve"
SUMMARY = "Gitlab webhook for automatically approving merge requests."
19 changes: 10 additions & 9 deletions autoapprove/bootstrapping/app_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,26 @@
from middleware.exception_logger_middleware import ExceptionLoggerMiddleware
from app_info import VERSION, NAME, SUMMARY


class AppBuilder():
config: Config
logger: Logger

def with_config(self, config: Config) -> 'AppBuilder':
self.config = config
return self

def __configure_logging(self):
rootLogger: Logger = getLogger(None)
config = self.config.logging
if config.enable and config.handlers is not None:
handlers = config.handlers
rootLogger = create_logger(rootLogger,
config.getLogLevel(),
handlers.console is not None and handlers.console.enable,
handlers.file is not None and handlers.file.enable,
handlers.file.logfile if handlers.file is not None else "")
rootLogger = create_logger(rootLogger,
config.getLogLevel(),
handlers.console is not None and handlers.console.enable,
handlers.file is not None and handlers.file.enable,
handlers.file.logfile if handlers.file is not None else "")

def __configure_app(self, app: FastAPI):
app.add_middleware(ExceptionLoggerMiddleware)

Expand All @@ -38,7 +39,7 @@ def __configure_app(self, app: FastAPI):
if self.config.ssl.enable:
self.logger.info("Enabling HTTPS redirection")
enable_https_redirection(app)

origin = str(self.config.gitlab.host)
self.logger.info('Enabling CORS with allowed origin set to "%s"', origin)
enable_cors(app, origins=[origin])
Expand All @@ -56,4 +57,4 @@ def build(self) -> FastAPI:
self.logger.info("Configuring app")
self.__configure_app(app)

return app
return app
3 changes: 2 additions & 1 deletion autoapprove/config/commands/approval.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from config.commands.respondable_command import RespondableCommand


class Approval(RespondableCommand):
pass
pass
3 changes: 2 additions & 1 deletion autoapprove/config/commands/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
from config.validators.string_list_not_empty import string_list_not_empty
from config.gitlab.gitlab_role import GitlabRole


class Command(ABC, BaseModel):
keyword: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
ignore_case: bool
strict_match: bool
only_for_members: list[str] | None = None
requires_role: GitlabRole | None = None

_string_list_not_empty = validator('ONLY_FOR_MEMBERS', allow_reuse=True, check_fields=False)(string_list_not_empty)
_string_list_not_empty = validator('ONLY_FOR_MEMBERS', allow_reuse=True, check_fields=False)(string_list_not_empty)
3 changes: 2 additions & 1 deletion autoapprove/config/commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from config.commands.disapproval import Disapproval
from config.commands.merge import Merge


class Commands(BaseModel):
approval: Approval
disapproval: Disapproval
merge: Merge
merge: Merge
3 changes: 2 additions & 1 deletion autoapprove/config/commands/disapproval.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from config.commands.respondable_command import RespondableCommand


class Disapproval(RespondableCommand):
pass
pass
3 changes: 2 additions & 1 deletion autoapprove/config/commands/merge.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from config.commands.respondable_command import RespondableCommand


class Merge(RespondableCommand):
pass
pass
3 changes: 2 additions & 1 deletion autoapprove/config/commands/respondable_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
from typing import Annotated
from config.commands.command import Command


class RespondableCommand(Command, ABC):
message: Annotated[str | None, StringConstraints(strip_whitespace=True, min_length=1)] = None
message: Annotated[str | None, StringConstraints(strip_whitespace=True, min_length=1)] = None
3 changes: 2 additions & 1 deletion autoapprove/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
from config.uvicorn import Uvicorn
from config.logging.logging import Logging


class Config(BaseModel):
gitlab: Gitlab
trusted_hosts_only: bool
environment: Environment
ssl: SSL
commands: Commands
uvicorn: Uvicorn
logging: Logging
logging: Logging
5 changes: 4 additions & 1 deletion autoapprove/config/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

_config: Config | None = None


def _load_config(filename: str, logger: Logger) -> Config:
try:
logger.info('Loading configuration from file "%s"', filename)
Expand All @@ -19,11 +20,13 @@ def _load_config(filename: str, logger: Logger) -> Config:
logger.error('Failed to load configuration', exc_info=e)
raise Exception("Failed to load configuration file. Please check your settings")


def init(filename: str, logger: Logger):
global _config
_config = _load_config(filename, logger)


def get_config() -> Config:
if _config is None:
raise Exception("Configuration has not been loaded")
return _config
return _config
3 changes: 2 additions & 1 deletion autoapprove/config/environment.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from enum import Enum


class Environment(str, Enum):
DEVELOPMENT = 'DEVELOPMENT'
PRODUCTION = 'PRODUCTION'
PRODUCTION = 'PRODUCTION'
10 changes: 7 additions & 3 deletions autoapprove/config/environment_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
from config.config import Config
from helpers.type import is_of_type_or_generic_of_type, is_optional, unpack_optional


def _parse_as_list(value: str) -> list[str]:
value = value.strip("[]")
return [x.strip() for x in value.split(',') if len(x.strip()) > 0]


def _load_environment_variable(section: dict[str, Any], env_var_name: str, attribute: str, type: type) -> bool:
value: str = environ.get(env_var_name, None)
if value is None or len(value.strip()) == 0:
return False

value = value.strip()
if is_optional(type):
type = unpack_optional(type)
Expand All @@ -23,6 +25,7 @@ def _load_environment_variable(section: dict[str, Any], env_var_name: str, attri
section[attribute] = value
return True


def _is_model(t: type) -> (bool, type):
model_type: type = t
if is_optional(t):
Expand All @@ -31,13 +34,14 @@ def _is_model(t: type) -> (bool, type):
return True, model_type
return False, None


def _load_environment_helper(section: dict[str, Any], section_type: BaseModel, separator: str, prefix: str = "") -> bool:
loaded_field = False
for field_name, field_info in section_type.model_fields.items():
field_type = field_info.annotation
is_model, model_type = _is_model(field_type)
if is_model:
field_was_none = not field_name in section
field_was_none = field_name not in section
if field_was_none:
section[field_name] = dict()
loaded_sub_field = _load_environment_helper(section[field_name], cast(BaseModel, model_type), separator, f"{prefix}{field_name}{separator}")
Expand All @@ -49,4 +53,4 @@ def _load_environment_helper(section: dict[str, Any], section_type: BaseModel, s


def load_environment(config: dict[str, Any], separator: str = "__"):
_load_environment_helper(config, Config, separator)
_load_environment_helper(config, Config, separator)
3 changes: 2 additions & 1 deletion autoapprove/config/gitlab/gitlab.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from pydantic import BaseModel, StringConstraints, HttpUrl
from typing import Annotated


class Gitlab(BaseModel):
host: HttpUrl
access_token: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
webhook_token: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
webhook_token: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
4 changes: 3 additions & 1 deletion autoapprove/config/gitlab/gitlab_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

ROLE_MAPPINGS = dict()


class GitlabRole(str, Enum):
NO_ACCESS = 'NO_ACCESS'
MINIMAL_ACCESS = 'MINIMAL_ACCESS'
Expand All @@ -15,10 +16,11 @@ class GitlabRole(str, Enum):
def get_role(self):
return ROLE_MAPPINGS[self]


ROLE_MAPPINGS[GitlabRole.NO_ACCESS] = Role.NO_ACCESS
ROLE_MAPPINGS[GitlabRole.MINIMAL_ACCESS] = Role.MINIMAL_ACCESS
ROLE_MAPPINGS[GitlabRole.GUEST] = Role.GUEST
ROLE_MAPPINGS[GitlabRole.REPORTER] = Role.REPORTER
ROLE_MAPPINGS[GitlabRole.DEVELOPER] = Role.DEVELOPER
ROLE_MAPPINGS[GitlabRole.MAINTAINER] = Role.MAINTAINER
ROLE_MAPPINGS[GitlabRole.OWNER] = Role.OWNER
ROLE_MAPPINGS[GitlabRole.OWNER] = Role.OWNER
3 changes: 2 additions & 1 deletion autoapprove/config/logging/console_handler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from config.logging.handler import Handler


class ConsoleHandler(Handler):
pass
pass
3 changes: 2 additions & 1 deletion autoapprove/config/logging/file_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from pathlib import Path
from config.logging.handler import Handler


class FileHandler(Handler):
logfile: Path | None = None

@model_validator(mode='after')
def _validate(self) -> 'FileHandler':
if self.enable and self.logfile is None:
raise ValidationError("Log file must be specified when enabling file handler")
return self
return self
3 changes: 2 additions & 1 deletion autoapprove/config/logging/handler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pydantic import BaseModel


class Handler(BaseModel):
enable: bool
enable: bool
3 changes: 2 additions & 1 deletion autoapprove/config/logging/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from config.logging.file_handler import FileHandler
from config.logging.console_handler import ConsoleHandler


class Handlers(BaseModel):
console: ConsoleHandler | None = None
file: FileHandler | None = None
file: FileHandler | None = None
8 changes: 3 additions & 5 deletions autoapprove/config/logging/logging.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from pydantic import BaseModel, model_validator, ValidationError
from config.logging.handlers import Handlers
from logging import getLevelNamesMapping
from helpers.logging.level import get_level_from_name


class Logging(BaseModel):
enable: bool
level: str | None = None
handlers: Handlers | None = None
_level: int | None = None


@model_validator(mode='after')
def _validate(self) -> 'Logging':
Expand All @@ -20,9 +19,8 @@ def _validate(self) -> 'Logging':
if level is None:
raise ValidationError("Invalid log level")
self._level = level

return self


def getLogLevel(self) -> int:
return self._level
return self._level
3 changes: 2 additions & 1 deletion autoapprove/config/ssl.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pydantic import BaseModel, model_validator, FilePath, ValidationError


class SSL(BaseModel):
enable: bool
key_file: FilePath | None = None
Expand All @@ -9,4 +10,4 @@ class SSL(BaseModel):
def _validate_certs(self) -> 'SSL':
if self.enable and (self.key_file is None or self.cert_file is None):
raise ValidationError("Certificate and key file are required with SSL enabled")
return self
return self
Loading

0 comments on commit 7c50059

Please sign in to comment.