diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..2fadfb31 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +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 black==23.7.0 \ + isort==5.12.0 \ + mypy==1.5.1 \ + pylint==2.17.5 \ + pytest==7.4.2 \ + tutor==16.1.2 \ + types-docutils==0.20.0.3 \ + types-pyyaml==6.0.12.11 \ + types-setuptools==68.1.0.0 + - name: Test lint, types, and format + run: make test diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..625c9d1a --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +.DEFAULT_GOAL := help +.PHONY: docs +SRC_DIRS = ./tutormfe +BLACK_OPTS = --exclude templates ${SRC_DIRS} + +# Warning: These checks are 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/20231004_141842_codewithemad_test_lint.md b/changelog.d/20231004_141842_codewithemad_test_lint.md new file mode 100644 index 00000000..81ca4f19 --- /dev/null +++ b/changelog.d/20231004_141842_codewithemad_test_lint.md @@ -0,0 +1 @@ +- [Improvement] Added Makefile and test action to repository and formatted code with Black and isort. (by @CodeWithEmad) \ No newline at end of file diff --git a/tutormfe/hooks.py b/tutormfe/hooks.py index bdd6d8d6..c7a6b5e2 100644 --- a/tutormfe/hooks.py +++ b/tutormfe/hooks.py @@ -4,11 +4,11 @@ them. """ from __future__ import annotations + import typing as t from tutor.core.hooks import Filter - -MFE_ATTRS_TYPE = t.Dict[t.Literal["repository", "port"], t.Union["str", int]] +MFE_ATTRS_TYPE = t.Dict[t.Literal["repository", "refs", "port"], t.Union["str", int]] MFE_APPS: Filter[dict[str, MFE_ATTRS_TYPE], []] = Filter() diff --git a/tutormfe/plugin.py b/tutormfe/plugin.py index 7df6b8f3..4433b0c2 100644 --- a/tutormfe/plugin.py +++ b/tutormfe/plugin.py @@ -1,17 +1,17 @@ from __future__ import annotations -from glob import glob import os import typing as t +from glob import glob import pkg_resources - from tutor import fmt from tutor import hooks as tutor_hooks from tutor.hooks import priorities from tutor.types import Config, get_typed + from .__about__ import __version__, __version_suffix__ -from .hooks import MFE_ATTRS_TYPE, MFE_APPS +from .hooks import MFE_APPS, MFE_ATTRS_TYPE config = { "defaults": { @@ -24,55 +24,64 @@ } -# If the package version suffix is set (for instance, in the nightly branch) use the "heads" Github refs API endpoint by default. -def gh_refs_path() -> str: - return "heads" if __version_suffix__ else "tags" +def get_github_refs_path(name: str) -> str: + """ + Generate a URL to access refs in heads (nightly) or tags (stable) via Github API. + Args: + name (str): Consisted of the repository owner and the repository name, as a string in 'owner/repo' format. + + Returns: + str: A string URL to the Github API, pointing to heads if version_suffix is set, tags otherwise. + + """ + + return f"https://api.github.com/repos/{name}/git/refs/{'heads' if __version_suffix__ else 'tags'}" CORE_MFE_APPS: dict[str, MFE_ATTRS_TYPE] = { "authn": { "repository": "https://github.com/openedx/frontend-app-authn", - "refs": "https://api.github.com/repos/openedx/frontend-app-authn/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-authn"), "port": 1999, }, "account": { "repository": "https://github.com/openedx/frontend-app-account", - "refs": "https://api.github.com/repos/openedx/frontend-app-account/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-account"), "port": 1997, }, "communications": { "repository": "https://github.com/openedx/frontend-app-communications", - "refs": "https://api.github.com/repos/openedx/frontend-app-communications/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-communications"), "port": 1984, }, "course-authoring": { "repository": "https://github.com/openedx/frontend-app-course-authoring", - "refs": "https://api.github.com/repos/openedx/frontend-app-course-authoring/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-course-authoring"), "port": 2001, }, "discussions": { "repository": "https://github.com/openedx/frontend-app-discussions", - "refs": "https://api.github.com/repos/openedx/frontend-app-discussions/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-discussions"), "port": 2002, }, "gradebook": { "repository": "https://github.com/openedx/frontend-app-gradebook", - "refs": "https://api.github.com/repos/openedx/frontend-app-gradebook/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-gradebook"), "port": 1994, }, "learning": { "repository": "https://github.com/openedx/frontend-app-learning", - "refs": "https://api.github.com/repos/openedx/frontend-app-learning/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-learning"), "port": 2000, }, "ora-grading": { "repository": "https://github.com/openedx/frontend-app-ora-grading", - "refs": "https://api.github.com/repos/openedx/frontend-app-ora-grading/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-ora-grading"), "port": 1993, }, "profile": { "repository": "https://github.com/openedx/frontend-app-profile", - "refs": "https://api.github.com/repos/openedx/frontend-app-profile/git/refs/" + gh_refs_path(), + "refs": get_github_refs_path("openedx/frontend-app-profile"), "port": 1995, }, } @@ -161,7 +170,9 @@ def is_mfe_enabled(mfe_name: str) -> bool: @tutor_hooks.Filters.COMPOSE_MOUNTS.add() -def _mount_frontend_apps(volumes, path_basename): +def _mount_frontend_apps( + volumes: list[tuple[str, str]], path_basename: str +) -> list[tuple[str, str]]: """ If the user mounts any repo named frontend-app-APPNAME, then make sure it's available in the APPNAME service container. This is only applicable