diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2ff802d --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,22 @@ +name: Run tests + +on: + pull_request: + branches: [master] + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Upgrade pip + run: python -m pip install --upgrade pip setuptools + - name: Install dependencies + run: | + pip install 'tutor[dev]>=16.0.0,<17.0.0' + - name: Test lint, types, and format + run: make test diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..900866e --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +.DEFAULT_GOAL := help +.PHONY: docs +SRC_DIRS = ./tutorcairn +BLACK_OPTS = --exclude templates ${SRC_DIRS} + +# Warning: These checks are not necessarily run on every PR. +test: test-lint test-types test-format # Run some static checks. + +test-format: ## Run code formatting tests + black --check --diff $(BLACK_OPTS) + +test-lint: ## Run code linting tests + pylint --errors-only --enable=unused-import,unused-argument --ignore=templates --ignore=docs/_ext ${SRC_DIRS} + +test-types: ## Run type checks. + mypy --exclude=templates --ignore-missing-imports --implicit-reexport --strict ${SRC_DIRS} + +format: ## Format code automatically + black $(BLACK_OPTS) + +isort: ## Sort imports. This target is not mandatory because the output may be incompatible with black formatting. Provided for convenience purposes. + isort --skip=templates ${SRC_DIRS} + +changelog-entry: ## Create a new changelog entry. + scriv create + +changelog: ## Collect changelog entries in the CHANGELOG.md file. + scriv collect + +ESCAPE =  +help: ## Print this help + @grep -E '^([a-zA-Z_-]+:.*?## .*|######* .+)$$' Makefile \ + | sed 's/######* \(.*\)/@ $(ESCAPE)[1;31m\1$(ESCAPE)[0m/g' | tr '@' '\n' \ + | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[33m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/changelog.d/20231118_181548_codewithemad_test_lint.md b/changelog.d/20231118_181548_codewithemad_test_lint.md new file mode 100644 index 0000000..952a383 --- /dev/null +++ b/changelog.d/20231118_181548_codewithemad_test_lint.md @@ -0,0 +1 @@ +- [Improvement] Added Typing to code, Makefile and test action to the repository and formatted code with Black and isort. (by @CodeWithEmad) \ No newline at end of file diff --git a/setup.py b/setup.py index 5f0f570..b4d403c 100644 --- a/setup.py +++ b/setup.py @@ -55,4 +55,4 @@ def load_about(): "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ], -) \ No newline at end of file +) diff --git a/tutorcairn/patches/openedx-lms-production-settings b/tutorcairn/patches/openedx-lms-production-settings deleted file mode 100644 index ae36ecc..0000000 --- a/tutorcairn/patches/openedx-lms-production-settings +++ /dev/null @@ -1 +0,0 @@ -CORS_ORIGIN_WHITELIST.append("{% if ENABLE_HTTPS %}https://{% else %}http://{% endif %}{{ CAIRN_HOST }}") diff --git a/tutorcairn/plugin.py b/tutorcairn/plugin.py index 75a6291..e54e704 100644 --- a/tutorcairn/plugin.py +++ b/tutorcairn/plugin.py @@ -1,12 +1,12 @@ from __future__ import annotations -from glob import glob + import os import shlex import typing as t +from glob import glob import click import pkg_resources - from tutor import hooks from tutor.__about__ import __version_suffix__ @@ -18,51 +18,53 @@ HERE = os.path.abspath(os.path.dirname(__file__)) - -hooks.Filters.CONFIG_UNIQUE.add_items( - [ - ("CAIRN_CLICKHOUSE_PASSWORD", "{{ 20|random_string }}"), - ("CAIRN_POSTGRESQL_PASSWORD", "{{ 20|random_string }}"), - ("CAIRN_SUPERSET_SECRET_KEY", "{{ 20|random_string }}"), - ("CAIRN_SSO_CLIENT_SECRET", "{{ 20|random_string }}"), - ] -) -hooks.Filters.CONFIG_DEFAULTS.add_items( - [ - ("CAIRN_VERSION", __version__), - ("CAIRN_DOCKER_HOST_SOCK_PATH", "/var/run/docker.sock"), - ("CAIRN_HOST", "data.{{ LMS_HOST }}"), +config: t.Dict[str, t.Dict[str, t.Any]] = { + "defaults": { + "VERSION": __version__, + "DOCKER_HOST_SOCK_PATH": "/var/run/docker.sock", + "HOST": "data.{{ LMS_HOST }}", # Clickhouse - ("CAIRN_RUN_CLICKHOUSE", True), - ( - "CAIRN_CLICKHOUSE_DOCKER_IMAGE", - "{{ DOCKER_REGISTRY }}overhangio/cairn-clickhouse:{{ CAIRN_VERSION }}", - ), - ("CAIRN_CLICKHOUSE_HOST", "cairn-clickhouse"), - ("CAIRN_CLICKHOUSE_HTTP_PORT", 8123), - ("CAIRN_CLICKHOUSE_HTTP_SCHEME", "http"), - ("CAIRN_CLICKHOUSE_PORT", 9000), - ("CAIRN_CLICKHOUSE_DATABASE", "openedx"), - ("CAIRN_CLICKHOUSE_USERNAME", "openedx"), + "RUN_CLICKHOUSE": True, + "CLICKHOUSE_DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/cairn-clickhouse:{{ CAIRN_VERSION }}", + "CLICKHOUSE_HOST": "cairn-clickhouse", + "CLICKHOUSE_HTTP_PORT": 8123, + "CLICKHOUSE_HTTP_SCHEME": "http", + "CLICKHOUSE_PORT": 9000, + "CLICKHOUSE_DATABASE": "openedx", + "CLICKHOUSE_USERNAME": "openedx", # Superset/Postgresql - ("CAIRN_RUN_POSTGRESQL", True), - ("CAIRN_POSTGRESQL_DATABASE", "superset"), - ("CAIRN_POSTGRESQL_USERNAME", "superset"), - ( - "CAIRN_SUPERSET_DOCKER_IMAGE", - "{{ DOCKER_REGISTRY }}overhangio/cairn-superset:{{ CAIRN_VERSION }}", - ), - ("CAIRN_SUPERSET_LANGUAGE_CODE", "{{ LANGUAGE_CODE[:2] }}"), + "RUN_POSTGRESQL": True, + "POSTGRESQL_DATABASE": "superset", + "POSTGRESQL_USERNAME": "superset", + "SUPERSET_DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/cairn-superset:{{ CAIRN_VERSION }}", + "SUPERSET_LANGUAGE_CODE": "{{ LANGUAGE_CODE[:2] }}", # SSO - ("CAIRN_ENABLE_SSO", True), - ("CAIRN_SSO_CLIENT_ID", "cairn"), + "ENABLE_SSO": True, + "SSO_CLIENT_ID": "cairn", # Vector # https://hub.docker.com/r/timberio/vector/tags # https://github.com/vectordotdev/vector/releases - ("CAIRN_VECTOR_DOCKER_IMAGE", "docker.io/timberio/vector:0.25.1-alpine"), - #Auto sync user roles - ("CAIRN_AUTH_ROLES_SYNC_AT_LOGIN", False), - ] + "VECTOR_DOCKER_IMAGE": "docker.io/timberio/vector:0.25.1-alpine", + # Auto sync user roles + "AUTH_ROLES_SYNC_AT_LOGIN": False, + }, + "unique": { + "CLICKHOUSE_PASSWORD": "{{ 20|random_string }}", + "POSTGRESQL_PASSWORD": "{{ 20|random_string }}", + "SUPERSET_SECRET_KEY": "{{ 20|random_string }}", + "SSO_CLIENT_SECRET": "{{ 20|random_string }}", + }, +} + +# Add configuration entries +hooks.Filters.CONFIG_DEFAULTS.add_items( + [(f"CAIRN_{key}", value) for key, value in config.get("defaults", {}).items()] +) +hooks.Filters.CONFIG_UNIQUE.add_items( + [(f"CAIRN_{key}", value) for key, value in config.get("unique", {}).items()] +) +hooks.Filters.CONFIG_OVERRIDES.add_items( + list(config.get("overrides", {}).items()) ) # Init scripts @@ -118,7 +120,9 @@ @hooks.Filters.APP_PUBLIC_HOSTS.add() -def _print_superset_host(hosts: list[str], context_name: t.Literal["local", "dev"]): +def _print_superset_host( + hosts: list[str], context_name: t.Literal["local", "dev"] +) -> list[str]: if context_name == "dev": hosts.append("{{ CAIRN_HOST }}:2247") else: @@ -152,7 +156,12 @@ def _print_superset_host(hosts: list[str], context_name: t.Literal["local", "dev @click.argument("username") @click.argument("email") def create_user_command( - bootstrap_dashboards: bool, admin: bool, password: str, course_ids: list[str], username: str, email: str + bootstrap_dashboards: bool, + admin: bool, + password: str, + course_ids: list[str], + username: str, + email: str, ) -> t.Iterable[tuple[str, str]]: admin_opt = " --admin" if admin else ""