diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 942440e..d4614ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,9 +5,9 @@ name: Python application on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] permissions: contents: read @@ -19,13 +19,12 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.11 uses: actions/setup-python@v3 with: - python-version: "3.10" + python-version: "3.11" - name: Install dependencies run: | - python -m pip install --upgrade pip python -m pip install -r requirements/test.txt - name: Run Test run: | diff --git a/.gitignore b/.gitignore index c30a72e..3c69372 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ terraform.tfvars # macOS .DS_Store + +# Ruff + .ruff_cache diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f632b6f..89b9661 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ default_language_version: python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.2.0" + rev: "v4.4.0" hooks: - id: check-added-large-files - id: check-case-conflict @@ -24,24 +24,17 @@ repos: - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/asottile/pyupgrade - rev: "v2.34.0" + rev: "v3.3.1" hooks: - id: pyupgrade args: [--py310-plus] - repo: https://github.com/psf/black - rev: "22.3.0" + rev: "22.12.0" hooks: - id: black - - repo: https://github.com/pycqa/isort - rev: "5.10.1" + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.218 hooks: - - id: isort - - repo: https://github.com/pycqa/flake8 - rev: "4.0.1" - hooks: - - id: flake8 - additional_dependencies: - - flake8-assertive~=2.1.0 - - flake8-bugbear~=22.4.25 - - flake8-docstrings~=1.6.0 - - flake8-isort~=4.1.0 + - id: ruff + args: + - --fix diff --git a/Dockerfile b/Dockerfile index ec7d3df..fa0fcaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10-slim-bullseye +FROM python:3.11-slim-bullseye ARG DEBIAN_FRONTEND=noninteractive ARG OUTPUT_BASE_DIR=/data diff --git a/Makefile b/Makefile index ffe024e..d4f8f1c 100644 --- a/Makefile +++ b/Makefile @@ -3,14 +3,12 @@ .PHONY: check check: ## Check code formatting and import sorting python3 -m black --check . - python3 -m isort --check . - python3 -m flake8 + ruff . .PHONY: fix fix: ## Fix code formatting, linting and sorting imports python3 -m black . - python3 -m isort . - python3 -m flake8 + ruff --fix . .PHONY: local local: pip_update ## Install local requirements and dependencies @@ -22,13 +20,13 @@ outdated: ## Check outdated requirements and dependencies .PHONY: pip pip: pip_update ## Compile requirements - python3 -m piptools compile --no-header --quiet --upgrade --output-file requirements/common.txt requirements/common.in - python3 -m piptools compile --no-header --quiet --upgrade --output-file requirements/local.txt requirements/local.in - python3 -m piptools compile --no-header --quiet --upgrade --output-file requirements/test.txt requirements/test.in + python3 -m piptools compile --no-header --quiet --resolver=backtracking --upgrade --output-file requirements/common.txt requirements/common.in + python3 -m piptools compile --no-header --quiet --resolver=backtracking --upgrade --output-file requirements/local.txt requirements/local.in + python3 -m piptools compile --no-header --quiet --resolver=backtracking --upgrade --output-file requirements/test.txt requirements/test.in .PHONY: pip_update pip_update: ## Update requirements and dependencies - python3 -m pip install -q -U pip~=22.0.0 pip-tools~=6.5.0 setuptools~=60.9.0 wheel~=0.37.0 + python3 -m pip install -q -U pip~=22.3.0 pip-tools~=6.12.0 setuptools~=65.6.0 wheel~=0.38.0 .PHONY: precommit precommit: ## Fix code formatting, linting and sorting imports diff --git a/bootstrap/constants.py b/bootstrap/constants.py index ab14371..a2632aa 100755 --- a/bootstrap/constants.py +++ b/bootstrap/constants.py @@ -1,6 +1,5 @@ """Web project initialization CLI constants.""" -from typing import Dict # Stacks @@ -39,7 +38,7 @@ DEV_ENV_SLUG = "dev" -DEV_ENV_STACK_CHOICES: Dict[str, str] = { +DEV_ENV_STACK_CHOICES: dict[str, str] = { "1": MAIN_STACK_SLUG, } @@ -47,7 +46,7 @@ STAGE_ENV_SLUG = "stage" -STAGE_ENV_STACK_CHOICES: Dict[str, str] = { +STAGE_ENV_STACK_CHOICES: dict[str, str] = { "1": MAIN_STACK_SLUG, "2": DEV_STACK_SLUG, } @@ -56,7 +55,7 @@ PROD_ENV_SLUG = "prod" -PROD_ENV_STACK_CHOICES: Dict[str, str] = {} +PROD_ENV_STACK_CHOICES: dict[str, str] = {} # Env vars diff --git a/bootstrap/runner.py b/bootstrap/runner.py index 896e9e9..3b8d7b3 100755 --- a/bootstrap/runner.py +++ b/bootstrap/runner.py @@ -222,7 +222,7 @@ def collect_vault_environment_secrets(self, env_name): """Collect the Vault secrets for the given environment.""" # Sentry env vars are used by the GitLab CI/CD self.sentry_dsn and self.register_vault_environment_secret( - env_name, f"{self.service_slug}/sentry", dict(sentry_dsn=self.sentry_dsn) + env_name, f"{self.service_slug}/sentry", {"sentry_dsn": self.sentry_dsn} ) def collect_vault_secrets(self): @@ -262,47 +262,49 @@ def create_env_file(self): def init_terraform_cloud(self): """Initialize the Terraform Cloud resources.""" click.echo(info("...creating the Terraform Cloud resources with Terraform")) - env = dict( - TF_VAR_admin_email=self.terraform_cloud_admin_email, - TF_VAR_create_organization=self.terraform_cloud_organization_create + env = { + "TF_VAR_admin_email": self.terraform_cloud_admin_email, + "TF_VAR_create_organization": self.terraform_cloud_organization_create and "true" or "false", - TF_VAR_environments=json.dumps(list(map(itemgetter("slug"), self.envs))), - TF_VAR_hostname=self.terraform_cloud_hostname, - TF_VAR_organization_name=self.terraform_cloud_organization, - TF_VAR_project_name=self.project_name, - TF_VAR_project_slug=self.project_slug, - TF_VAR_service_slug=self.service_slug, - TF_VAR_terraform_cloud_token=self.terraform_cloud_token, - ) + "TF_VAR_environments": json.dumps(list(map(itemgetter("slug"), self.envs))), + "TF_VAR_hostname": self.terraform_cloud_hostname, + "TF_VAR_organization_name": self.terraform_cloud_organization, + "TF_VAR_project_name": self.project_name, + "TF_VAR_project_slug": self.project_slug, + "TF_VAR_service_slug": self.service_slug, + "TF_VAR_terraform_cloud_token": self.terraform_cloud_token, + } self.run_terraform("terraform-cloud", env) def init_gitlab(self): """Initialize the GitLab repository and associated resources.""" click.echo(info("...creating the GitLab repository and associated resources")) - env = dict( - TF_VAR_gitlab_token=self.gitlab_private_token, - TF_VAR_gitlab_url=self.gitlab_url, - TF_VAR_group_path=self.gitlab_group_path, - TF_VAR_group_variables=self.render_gitlab_variables_to_string("group"), - TF_VAR_project_name=self.project_name, - TF_VAR_project_slug=self.project_slug, - TF_VAR_project_variables=self.render_gitlab_variables_to_string("project"), - TF_VAR_service_dir=self.service_dir, - TF_VAR_service_slug=self.service_slug, - ) + env = { + "TF_VAR_gitlab_token": self.gitlab_private_token, + "TF_VAR_gitlab_url": self.gitlab_url, + "TF_VAR_group_path": self.gitlab_group_path, + "TF_VAR_group_variables": self.render_gitlab_variables_to_string("group"), + "TF_VAR_project_name": self.project_name, + "TF_VAR_project_slug": self.project_slug, + "TF_VAR_project_variables": self.render_gitlab_variables_to_string( + "project" + ), + "TF_VAR_service_dir": self.service_dir, + "TF_VAR_service_slug": self.service_slug, + } self.run_terraform("gitlab", env) def init_vault(self): """Initialize the Vault resources.""" click.echo(info("...creating the Vault resources with Terraform")) self.collect_vault_secrets() - env = dict( - TF_VAR_project_slug=self.project_slug, - TF_VAR_secrets=json.dumps(self.vault_secrets), - TF_VAR_vault_address=self.vault_url, - TF_VAR_vault_token=self.vault_token, - ) + env = { + "TF_VAR_project_slug": self.project_slug, + "TF_VAR_secrets": json.dumps(self.vault_secrets), + "TF_VAR_vault_address": self.vault_url, + "TF_VAR_vault_token": self.vault_token, + } self.run_terraform("vault", env) def get_terraform_module_params(self, module_name, env): diff --git a/pyproject.toml b/pyproject.toml index 84002c4..3301cf5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,40 @@ [tool.black] -target-version = ["py310"] - -[tool.isort] -atomic = true -profile = "black" +target-version = ["py311"] [tool.mypy] -python_version = "3.10" +python_version = "3.11" ignore_missing_imports = true + +[tool.ruff] + extend-exclude = [ + "__pycache__", + ".vscode*", + ] + extend-ignore = [ + "D203", + "D212", + "D213", + "D214", + "D215", + "D404", + "D405", + "D406", + "D407", + "D408", + "D409", + "D410", + "D411", + "D413", + "D415", + "D416", + "D417", + "E501", + ] + select = ["B", "C", "D", "E", "F", "I", "W", "B9"] + target-version = "py311" + +[tool.ruff.isort] +combine-as-imports = true +known-first-party = [ + "bootstrap", +] diff --git a/requirements/common.in b/requirements/common.in index 4ffe79e..9147955 100644 --- a/requirements/common.in +++ b/requirements/common.in @@ -1,7 +1,7 @@ -black~=22.3.0 +black~=22.12.0 click~=8.1.0 cookiecutter~=2.1.0 -pip-tools~=6.6.0 -pydantic~=1.9.0 -types-python-slugify~=5.0.0 +pip-tools~=6.12.0 +pydantic~=1.10.0 +types-python-slugify~=7.0.0 validators~=0.20.0 diff --git a/requirements/common.txt b/requirements/common.txt index 5d28bdf..c63ae26 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -1,14 +1,16 @@ -arrow==1.2.2 +arrow==1.2.3 # via jinja2-time binaryornot==0.4.4 # via cookiecutter -black==22.3.0 +black==22.12.0 # via -r requirements/common.in -certifi==2022.6.15 +build==0.9.0 + # via pip-tools +certifi==2022.12.7 # via requests -chardet==5.0.0 +chardet==5.1.0 # via binaryornot -charset-normalizer==2.1.0 +charset-normalizer==2.1.1 # via requests click==8.1.3 # via @@ -20,7 +22,7 @@ cookiecutter==2.1.1 # via -r requirements/common.in decorator==5.1.1 # via validators -idna==3.3 +idna==3.4 # via requests jinja2==3.1.2 # via @@ -32,19 +34,21 @@ markupsafe==2.1.1 # via jinja2 mypy-extensions==0.4.3 # via black -pathspec==0.9.0 +packaging==23.0 + # via build +pathspec==0.10.3 # via black -pep517==0.12.0 - # via pip-tools -pip-tools==6.6.2 +pep517==0.13.0 + # via build +pip-tools==6.12.1 # via -r requirements/common.in -platformdirs==2.5.2 +platformdirs==2.6.2 # via black -pydantic==1.9.1 +pydantic==1.10.4 # via -r requirements/common.in python-dateutil==2.8.2 # via arrow -python-slugify==6.1.2 +python-slugify==7.0.0 # via cookiecutter pyyaml==6.0 # via cookiecutter @@ -54,19 +58,15 @@ six==1.16.0 # via python-dateutil text-unidecode==1.3 # via python-slugify -tomli==2.0.1 - # via - # black - # pep517 -types-python-slugify==5.0.4 +types-python-slugify==7.0.0.1 # via -r requirements/common.in -typing-extensions==4.3.0 +typing-extensions==4.4.0 # via pydantic -urllib3==1.26.9 +urllib3==1.26.13 # via requests validators==0.20.0 # via -r requirements/common.in -wheel==0.37.1 +wheel==0.38.4 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/local.in b/requirements/local.in index 1a20731..e9f9adf 100644 --- a/requirements/local.in +++ b/requirements/local.in @@ -1,4 +1,3 @@ -r test.in -ipdb~=0.13.0 -pre-commit~=2.19.0 -pyupgrade~=2.34.0 +ipython~=8.8.0 +pre-commit~=2.21.0 diff --git a/requirements/local.txt b/requirements/local.txt index 6db98d8..cd1c45e 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -1,22 +1,22 @@ -arrow==1.2.2 +arrow==1.2.3 # via jinja2-time -asttokens==2.0.5 +asttokens==2.2.1 # via stack-data -attrs==21.4.0 - # via flake8-bugbear backcall==0.2.0 # via ipython binaryornot==0.4.4 # via cookiecutter -black==22.3.0 +black==22.12.0 # via -r requirements/common.in -certifi==2022.6.15 +build==0.9.0 + # via pip-tools +certifi==2022.12.7 # via requests cfgv==3.3.1 # via pre-commit -chardet==5.0.0 +chardet==5.1.0 # via binaryornot -charset-normalizer==2.1.0 +charset-normalizer==2.1.1 # via requests click==8.1.3 # via @@ -26,44 +26,25 @@ click==8.1.3 # pip-tools cookiecutter==2.1.1 # via -r requirements/common.in -coverage[toml]==6.4.1 +coverage[toml]==7.0.5 # via -r requirements/test.in decorator==5.1.1 # via - # ipdb # ipython # validators -distlib==0.3.4 +distlib==0.3.6 # via virtualenv -executing==0.8.3 +executing==1.2.0 # via stack-data -filelock==3.7.1 +filelock==3.9.0 # via virtualenv -flake8==4.0.1 - # via - # -r requirements/test.in - # flake8-bugbear - # flake8-docstrings - # flake8-isort -flake8-bugbear==22.4.25 - # via -r requirements/test.in -flake8-docstrings==1.6.0 - # via -r requirements/test.in -flake8-isort==4.1.1 - # via -r requirements/test.in -identify==2.5.1 +identify==2.5.12 # via pre-commit -idna==3.3 +idna==3.4 # via requests -ipdb==0.13.9 +ipython==8.8.0 # via -r requirements/local.in -ipython==8.4.0 - # via ipdb -isort==5.10.1 - # via - # -r requirements/test.in - # flake8-isort -jedi==0.18.1 +jedi==0.18.2 # via ipython jinja2==3.1.2 # via @@ -73,11 +54,9 @@ jinja2-time==0.2.0 # via cookiecutter markupsafe==2.1.1 # via jinja2 -matplotlib-inline==0.1.3 +matplotlib-inline==0.1.6 # via ipython -mccabe==0.6.1 - # via flake8 -mypy==0.961 +mypy==0.991 # via -r requirements/test.in mypy-extensions==0.4.3 # via @@ -85,96 +64,75 @@ mypy-extensions==0.4.3 # mypy nodeenv==1.7.0 # via pre-commit +packaging==23.0 + # via build parso==0.8.3 # via jedi -pathspec==0.9.0 +pathspec==0.10.3 # via black -pep517==0.12.0 - # via pip-tools +pep517==0.13.0 + # via build pexpect==4.8.0 # via ipython pickleshare==0.7.5 # via ipython -pip-tools==6.6.2 +pip-tools==6.12.1 # via -r requirements/common.in -platformdirs==2.5.2 +platformdirs==2.6.2 # via # black # virtualenv -pre-commit==2.19.0 +pre-commit==2.21.0 # via -r requirements/local.in -prompt-toolkit==3.0.30 +prompt-toolkit==3.0.36 # via ipython ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data -pycodestyle==2.8.0 - # via flake8 -pydantic==1.9.1 +pydantic==1.10.4 # via -r requirements/common.in -pydocstyle==6.1.1 - # via flake8-docstrings -pyflakes==2.4.0 - # via flake8 -pygments==2.12.0 +pygments==2.14.0 # via ipython python-dateutil==2.8.2 # via arrow -python-slugify==6.1.2 +python-slugify==7.0.0 # via cookiecutter -pyupgrade==2.34.0 - # via -r requirements/local.in pyyaml==6.0 # via # cookiecutter # pre-commit requests==2.28.1 # via cookiecutter +ruff==0.0.218 + # via -r requirements/test.in six==1.16.0 # via # asttokens # python-dateutil - # virtualenv -snowballstemmer==2.2.0 - # via pydocstyle -stack-data==0.3.0 +stack-data==0.6.2 # via ipython -testfixtures==6.18.5 - # via flake8-isort text-unidecode==1.3 # via python-slugify -tokenize-rt==4.2.1 - # via pyupgrade -toml==0.10.2 - # via - # ipdb - # pre-commit -tomli==2.0.1 - # via - # black - # coverage - # mypy - # pep517 -traitlets==5.3.0 +traitlets==5.8.1 # via # ipython # matplotlib-inline -types-python-slugify==5.0.4 +types-python-slugify==7.0.0.1 # via -r requirements/common.in -typing-extensions==4.3.0 +typing-extensions==4.4.0 # via # mypy # pydantic -urllib3==1.26.9 +urllib3==1.26.13 # via requests validators==0.20.0 # via -r requirements/common.in -virtualenv==20.15.1 +virtualenv==20.17.1 # via pre-commit wcwidth==0.2.5 # via prompt-toolkit -wheel==0.37.1 +wheel==0.38.4 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/test.in b/requirements/test.in index c735f8c..89cce9b 100644 --- a/requirements/test.in +++ b/requirements/test.in @@ -1,8 +1,4 @@ -r common.in -coverage[toml]~=6.4.0 -flake8-bugbear~=22.4.0 -flake8-docstrings~=1.6.0 -flake8-isort~=4.1.0 -flake8~=4.0.0 -isort~=5.10.0 -mypy~=0.961 +coverage[toml]~=7.0.0 +ruff~=0.0.0 +mypy~=0.991 diff --git a/requirements/test.txt b/requirements/test.txt index 4b877c4..52a44c6 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,16 +1,16 @@ -arrow==1.2.2 +arrow==1.2.3 # via jinja2-time -attrs==21.4.0 - # via flake8-bugbear binaryornot==0.4.4 # via cookiecutter -black==22.3.0 +black==22.12.0 # via -r requirements/common.in -certifi==2022.6.15 +build==0.9.0 + # via pip-tools +certifi==2022.12.7 # via requests -chardet==5.0.0 +chardet==5.1.0 # via binaryornot -charset-normalizer==2.1.0 +charset-normalizer==2.1.1 # via requests click==8.1.3 # via @@ -20,28 +20,12 @@ click==8.1.3 # pip-tools cookiecutter==2.1.1 # via -r requirements/common.in -coverage[toml]==6.4.1 +coverage[toml]==7.0.5 # via -r requirements/test.in decorator==5.1.1 # via validators -flake8==4.0.1 - # via - # -r requirements/test.in - # flake8-bugbear - # flake8-docstrings - # flake8-isort -flake8-bugbear==22.4.25 - # via -r requirements/test.in -flake8-docstrings==1.6.0 - # via -r requirements/test.in -flake8-isort==4.1.1 - # via -r requirements/test.in -idna==3.3 +idna==3.4 # via requests -isort==5.10.1 - # via - # -r requirements/test.in - # flake8-isort jinja2==3.1.2 # via # cookiecutter @@ -50,63 +34,49 @@ jinja2-time==0.2.0 # via cookiecutter markupsafe==2.1.1 # via jinja2 -mccabe==0.6.1 - # via flake8 -mypy==0.961 +mypy==0.991 # via -r requirements/test.in mypy-extensions==0.4.3 # via # black # mypy -pathspec==0.9.0 +packaging==23.0 + # via build +pathspec==0.10.3 # via black -pep517==0.12.0 - # via pip-tools -pip-tools==6.6.2 +pep517==0.13.0 + # via build +pip-tools==6.12.1 # via -r requirements/common.in -platformdirs==2.5.2 +platformdirs==2.6.2 # via black -pycodestyle==2.8.0 - # via flake8 -pydantic==1.9.1 +pydantic==1.10.4 # via -r requirements/common.in -pydocstyle==6.1.1 - # via flake8-docstrings -pyflakes==2.4.0 - # via flake8 python-dateutil==2.8.2 # via arrow -python-slugify==6.1.2 +python-slugify==7.0.0 # via cookiecutter pyyaml==6.0 # via cookiecutter requests==2.28.1 # via cookiecutter +ruff==0.0.218 + # via -r requirements/test.in six==1.16.0 # via python-dateutil -snowballstemmer==2.2.0 - # via pydocstyle -testfixtures==6.18.5 - # via flake8-isort text-unidecode==1.3 # via python-slugify -tomli==2.0.1 - # via - # black - # coverage - # mypy - # pep517 -types-python-slugify==5.0.4 +types-python-slugify==7.0.0.1 # via -r requirements/common.in -typing-extensions==4.3.0 +typing-extensions==4.4.0 # via # mypy # pydantic -urllib3==1.26.9 +urllib3==1.26.13 # via requests validators==0.20.0 # via -r requirements/common.in -wheel==0.37.1 +wheel==0.38.4 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9bea51c..0000000 --- a/setup.cfg +++ /dev/null @@ -1,15 +0,0 @@ -[flake8] -exclude = - __pycache__, - .git, - .mypy_cache, - .pytest_cache, - .venv, - .vscode*, -ignore = E501,I003,T499,W503 -max-line-length = 80 -mypy_config = setup.cfg -select = B,C,D,E,F,I,W,T4,B9 - -[metadata] -license-file = LICENSE.md