diff --git a/.github/workflows/autoblack.yml b/.github/workflows/autoblack.yml deleted file mode 100644 index 761222b..0000000 --- a/.github/workflows/autoblack.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Check / auto apply Black -on: - push: - branches: - - master -jobs: - black: - name: Check / auto apply black - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check files using the black formatter - uses: psf/black@stable - id: black - with: - options: "." - continue-on-error: true - - shell: pwsh - id: check_files_changed - run: | - # Diff HEAD with the previous commit - $diff = git diff - $HasDiff = $diff.Length -gt 0 - Write-Host "::set-output name=files_changed::$HasDiff" - - name: Create Pull Request - if: steps.check_files_changed.outputs.files_changed == 'true' - uses: peter-evans/create-pull-request@v6 - with: - token: ${{ secrets.GITHUB_TOKEN }} - title: "Format Python code with Black" - commit-message: ":art: Format Python code with Black" - body: | - This pull request uses the [psf/black](https://github.com/psf/black) formatter. - base: ${{ github.head_ref }} # Creates pull request onto pull request or commit branch - branch: actions/black diff --git a/.github/workflows/python-check.yml b/.github/workflows/python-check.yml new file mode 100644 index 0000000..3c3445b --- /dev/null +++ b/.github/workflows/python-check.yml @@ -0,0 +1,28 @@ +name: Python Lint with Ruff and Mypy + +on: + pull_request: + push: + branches: [master] + +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + - name: Install Ruff and Mypy + run: pip install ruff mypy + + - name: Ruff check + run: | + ruff check . + + - name: Mypy install types + run: yes | mypy . --install-types || true + + - name: Mypy check + run: mypy . diff --git a/.github/workflows/python-format.yml b/.github/workflows/python-format.yml new file mode 100644 index 0000000..8ff8d9e --- /dev/null +++ b/.github/workflows/python-format.yml @@ -0,0 +1,34 @@ +name: Python formatting with Black and Ruff + +on: + push: + branches: [master] + +jobs: + format: + name: Formatting with Black and Ruff + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check files using the black formatter + uses: psf/black@stable + id: black + with: + options: "." + continue-on-error: true + + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + - name: Install Ruff + run: pip install ruff + + - name: Ruff check and fix + run: | + ruff check . + ruff check --fix . + + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: 'Python formatting fixes from Black and Ruff' diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index d4e239c..cd66aa5 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -2,6 +2,7 @@ name: Run Shellcheck on push and PR on: push: + branches: [master] pull_request: jobs: @@ -9,7 +10,7 @@ jobs: name: Shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master with: diff --git a/.gitignore b/.gitignore index 4ca7c29..c7e49c6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,8 @@ ssowat # Folders apps backup + + +__pycache__/ +.mypy_cache/ +.ruff_cache/ diff --git a/custom-catalog/catalog_manager.py b/custom-catalog/catalog_manager.py index 09baab7..70874ba 100755 --- a/custom-catalog/catalog_manager.py +++ b/custom-catalog/catalog_manager.py @@ -1,17 +1,18 @@ #!/usr/bin/python3 -import sys -import os import json -import toml -import yaml +import os +import sys import time from collections import OrderedDict +from pathlib import Path +from typing import Any + +import toml +import yaml -CATALOG_LIST_PATH = "/etc/yunohost/apps_catalog.yml" -assert os.path.exists( - CATALOG_LIST_PATH -), f"Catalog list yaml file '{CATALOG_LIST_PATH} does not exists" +CATALOG_LIST_PATH = Path("/etc/yunohost/apps_catalog.yml").resolve() +assert CATALOG_LIST_PATH.exists(), f"Catalog list yaml file '{CATALOG_LIST_PATH} does not exists" now = time.time() my_env = os.environ.copy() @@ -21,13 +22,14 @@ DEFAULT_APP_BRANCH = "master" -def build(folder=DEFAULT_APPS_FOLDER): - assert os.path.exists(folder), f"'{folder}' doesn't exists." +def build(folder: Path | str = DEFAULT_APPS_FOLDER) -> None: + folder = Path(folder) + assert folder.exists(), f"'{folder}' doesn't exists." - app_list_path = os.path.join(folder, "apps.json") - assert os.path.exists(app_list_path), "no 'apps.json' app list found." + app_list_path = folder / "apps.json" + assert app_list_path.exists(), "no 'apps.json' app list found." - with open(app_list_path) as f: + with app_list_path.open() as f: app_list = json.load(f) apps = {} @@ -44,37 +46,38 @@ def build(folder=DEFAULT_APPS_FOLDER): apps[app_dict["id"]] = app_dict - # We also remove the app install question and resources parts which aint needed anymore by webadmin etc (or at least we think ;P) + # We also remove the app install question and resources parts which aint needed + # anymore by webadmin etc (or at least we think ;P) for app in apps.values(): if "manifest" in app and "install" in app["manifest"]: del app["manifest"]["install"] if "manifest" in app and "resources" in app["manifest"]: del app["manifest"]["resources"] - output_file = os.path.join(folder, "catalog.json") + output_file = folder / "catalog.json" data = { "apps": apps, "from_api_version": 3, } - with open(output_file, "w") as f: + with output_file.open("w") as f: f.write(json.dumps(data, sort_keys=True, indent=2)) if fail: sys.exit(1) -def build_app_dict(app, infos, folder): - app_folder = os.path.join(folder, app + "_ynh") +def build_app_dict(app: str, infos: dict[str, Any], folder: Path) -> dict[str, Any]: + app_folder = folder / f"{app}_ynh" # Build the dict with all the infos - manifest_toml = os.path.join(app_folder, "manifest.toml") - manifest_json = os.path.join(app_folder, "manifest.json") - if os.path.exists(manifest_toml): - with open(manifest_toml) as f: + manifest_toml = app_folder / "manifest.toml" + manifest_json = app_folder / "manifest.json" + if manifest_toml.exists(): + with manifest_toml.open() as f: manifest = toml.load(f, _dict=OrderedDict) else: - with open(manifest_json) as f: + with manifest_json.open() as f: manifest = json.load(f, _dict=OrderedDict) return { @@ -94,32 +97,27 @@ def build_app_dict(app, infos, folder): "category": infos.get("category", None), "subtags": infos.get("subtags", []), "potential_alternative_to": infos.get("potential_alternative_to", []), - "antifeatures": list( - set( - list(manifest.get("antifeatures", {}).keys()) - + infos.get("antifeatures", []) - ) - ), + "antifeatures": list(set(list(manifest.get("antifeatures", {}).keys()) + infos.get("antifeatures", []))), } -def reset(): - with open(CATALOG_LIST_PATH, "w") as f: +def reset() -> None: + with CATALOG_LIST_PATH.open("w") as f: catalog_list = [{"id": "default", "url": "https://app.yunohost.org/default/"}] yaml.safe_dump(catalog_list, f, default_flow_style=False) -def add(): - with open(CATALOG_LIST_PATH) as f: +def add() -> None: + with CATALOG_LIST_PATH.open("r") as f: catalog_list = yaml.load(f, Loader=yaml.FullLoader) ids = [catalog["id"] for catalog in catalog_list] if "custom" not in ids: catalog_list.append({"id": "custom", "url": None}) - with open(CATALOG_LIST_PATH, "w") as f: + with CATALOG_LIST_PATH.open("w") as f: yaml.safe_dump(catalog_list, f, default_flow_style=False) -def override(): - with open(CATALOG_LIST_PATH, "w") as f: +def override() -> None: + with CATALOG_LIST_PATH.open("w") as f: catalog_list = [{"id": "custom", "url": None}] yaml.safe_dump(catalog_list, f, default_flow_style=False) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a015222 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[tool.black] +line-length = 120 + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = [ + "F", # pyflakes + "E", # pycodestyle + "W", # pycodestyle + "I", # isort + "N", # pep8-naming + "B", # flake8-ubgbear + "ANN", # flake8-annotations + "Q", # flake8-quotes + "PTH", # flake8-use-pathlib + "UP", # pyupgrade, +] + +[tool.mypy]