diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 4c3ffd0..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,60 +0,0 @@ -version: 2 - -jobs: - flake8: - docker: - - image: circleci/python:3.8 - steps: - - checkout - - run: pip install flake8 - - run: flake8 wagtail_localize_git - - test: - docker: - - image: circleci/python:3.8 - steps: - - checkout - - - type: cache-restore - keys: - - pip-{{ .Branch }}- - - pip-master- - - - run: pip install -e .[testing] - - - type: cache-save - key: pip-{{ .Branch }}-{{ epoch }} - paths: - - "~/.cache/pip" - - - run: python testmanage.py test - - nightly-wagtail-test: - docker: - - image: circleci/python:3.8 - steps: - - checkout - - run: git clone git@github.com:wagtail/wagtail.git - - - run: pip install -e .[testing] - - run: pip install ./wagtail - - - run: python testmanage.py test - -workflows: - version: 2 - test: - jobs: - - flake8 - - test - - nightly: - jobs: - - nightly-wagtail-test - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master diff --git a/.circleci/trigger-nightly-build.sh b/.circleci/trigger-nightly-build.sh deleted file mode 100755 index ef1accd..0000000 --- a/.circleci/trigger-nightly-build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# Triggers a test run against the master version of Wagtail - -# This job will is scheduled in the config.yml, this script is here to help test the job - -curl -u ${CIRCLE_API_USER_TOKEN}: \ - -d build_parameters[CIRCLE_JOB]=nightly-wagtail-test \ - https://circleci.com/api/v1.1/project/github/wagtail/wagtail-localize-git}/tree/master diff --git a/.coveragerc b/.coveragerc index b0b5879..ee2b6d6 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,17 +1,27 @@ [run] branch = True -include = wagtail_localize_git/* -omit = */migrations/*,*/tests/* +concurrency = multiprocessing, thread +parallel = True +source_pkgs = wagtail_localize_git +omit = **/migrations/*,tests/* + +[paths] +source = src,.tox/py*/**/site-packages [report] +show_missing = True +ignore_errors = True +skip_covered = True + # Regexes for lines to exclude from consideration -exclude_lines = +exclude_also = # Have to re-enable the standard pragma pragma: no cover # Don't complain about missing debug-only code: def __repr__ - if self\.debug + if self.debug + if settings.DEBUG # Don't complain if tests don't hit defensive assertion code: raise AssertionError @@ -21,4 +31,7 @@ exclude_lines = if 0: if __name__ == .__main__.: -ignore_errors = True + # Nor complain about type checking + "if TYPE_CHECKING:", + class .*\bProtocol\): + @(abc\.)?abstractmethod diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0742c41..da3c2e6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,33 +2,50 @@ name: Publish to PyPI on: release: - types: [released, prereleased] - -permissions: - contents: read # to fetch code (actions/checkout) + types: [published] jobs: - build_and_publish: + build: runs-on: ubuntu-latest + permissions: + contents: read # to fetch code (actions/checkout) steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Set up Python 3.8 - uses: actions/setup-python@v4 + - uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.11' + cache: "pip" + cache-dependency-path: "**/pyproject.toml" - - name: Install dependencies + - name: ⬇️ Install build dependencies run: | - python -m pip install --upgrade pip - python -m pip install wheel - - name: Build - run: python setup.py sdist bdist_wheel + python -m pip install flit + + - name: 🏗️ Build + run: python -m flit build + + - uses: actions/upload-artifact@v3 + with: + path: ./dist + + # https://docs.pypi.org/trusted-publishers/using-a-publisher/ + pypi-publish: + needs: build + environment: 'publish' + + name: ⬆️ Upload release to PyPI + runs-on: ubuntu-latest + permissions: + # Mandatory for trusted publishing + id-token: write + steps: + - uses: actions/download-artifact@v3 - - name: Publish to PyPI + - name: 🚀 Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - user: '__token__' - password: ${{ secrets.PYPI_API_TOKEN }} + packages-dir: artifact/ + print-hash: true diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000..298f8c6 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,21 @@ +name: Ruff + +on: + push: + - main + - 'stable/**' + pull_request: + branches: [main] + +jobs: + ruff: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - run: python -Im pip install --user ruff + + - name: Run ruff + working-directory: ./src + run: ruff --output-format=github wagtail_localize_git diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f21f91..7da585e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,7 @@ on: branches: - main - 'stable/**' + pull_request: branches: [main] @@ -12,6 +13,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read # to fetch code (actions/checkout) env: FORCE_COLOR: '1' # Make tools pretty. @@ -20,47 +23,47 @@ env: PIP_NO_PYTHON_VERSION_WARNING: '1' PYTHON_LATEST: '3.11' - jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: actions/setup-python@v4 - with: - python-version: ${{ env.PYTHON_LATEST }} - - uses: pre-commit/action@v3.0.0 - test-sqlite: runs-on: ubuntu-latest - needs: lint strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + db: ["sqlite"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox tox-py tox-venv + python -Im pip install --upgrade pip + python -Im pip install flit tox tox-gh-actions + python -Im flit install --symlink + + - name: 🏗️ Build wheel + run: python -Im flit build --format wheel + - name: Test - run: | - tox --py current + run: tox --installpkg ./dist/*.whl + + - name: ⬆️ Upload coverage data + uses: actions/upload-artifact@v3 + with: + name: coverage-data + path: .coverage.* + if-no-files-found: ignore + retention-days: 1 test-postgres: runs-on: ubuntu-latest - needs: lint strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + db: ["sqlite"] services: postgres: @@ -74,15 +77,60 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox tox-py tox-venv - - name: Run tox targets for Python ${{ matrix.python-version }} - run: | - tox --py current + python -Im pip install --upgrade pip + python -Im pip install flit tox tox-gh-actions + python -Im flit install --symlink + + - name: 🏗️ Build wheel + run: python -Im flit build --format wheel + + - name: Test env: DATABASE_URL: postgres://postgres:postgres@localhost:5432/wagtail_localize_git + run: tox --installpkg ./dist/*.whl + + - name: ⬆️ Upload coverage data + uses: actions/upload-artifact@v3 + with: + name: coverage-data + path: .coverage.* + if-no-files-found: ignore + retention-days: 1 + + coverage: + runs-on: ubuntu-latest + needs: + - test-sqlite + - test-postgres + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + # Use latest Python, so it understands all syntax. + python-version: ${{env.PYTHON_LATEST}} + + - run: python -Im pip install --upgrade coverage + + - name: ⬇️ Download coverage data + uses: actions/download-artifact@v3 + with: + name: coverage-data + + - name: + Combine coverage + run: | + python -Im coverage combine + python -Im coverage html --skip-covered --skip-empty + python -Im coverage report + echo "## Coverage summary" >> $GITHUB_STEP_SUMMARY + python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY + - name: 📈 Upload HTML report + uses: actions/upload-artifact@v3 + with: + name: html-report + path: htmlcov diff --git a/.gitignore b/.gitignore index 763af21..4a0fce8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ /build /dist /wagtail_localize_git.egg-info -/.coverage +.coverage +.coverage.* /htmlcov /.tox /venv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e02526..54950f6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,9 @@ +ci: + autofix_prs: false + default_language_version: python: python3.11 + repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 @@ -14,26 +18,9 @@ repos: args: ["--unsafe"] - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/psf/black - rev: 23.12.1 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: 'v0.1.13' hooks: - - id: black - args: ['--target-version', 'py38'] - - repo: https://github.com/pycqa/isort - # isort config is in setup.cfg - rev: 5.13.2 - hooks: - - id: isort - - repo: https://github.com/pycqa/flake8 - # flake8 config is in setup.cfg - rev: 7.0.0 - hooks: - - id: flake8 - additional_dependencies: - - flake8-bugbear - - flake8-comprehensions - - repo: https://github.com/asottile/blacken-docs - rev: 1.16.0 - hooks: - - id: blacken-docs - additional_dependencies: [black==23.12.1] + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index b59be30..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include LICENSE *.rst *.txt *.md -graft wagtail_localize_git -global-exclude __pycache__ -global-exclude *.py[co] diff --git a/README.md b/README.md index d0d4cc4..eda7b30 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This is useful for when you are using external translation tools for translating ## Installation -This plugin requires Wagtail >= 2.15 with [internationalisation enabled](https://docs.wagtail.org/en/stable/advanced_topics/i18n.html#configuration) and [Wagtail Localize](https://github.com/wagtail/wagtail-localize). +This plugin requires Wagtail >= 5.2 with [internationalisation enabled](https://docs.wagtail.org/en/stable/advanced_topics/i18n.html#configuration) and [Wagtail Localize](https://github.com/wagtail/wagtail-localize). Install both `wagtail-localize` and `wagtail-localize-git`, then add the following to your `INSTALLED_APPS`: @@ -90,7 +90,7 @@ Now you can run tests as shown below: tox ``` -or, you can run them for a specific environment `tox -e python3.9-django3.2-wagtail2.15` or specific test -`tox -e python3.9-django3.2-wagtail2.15-sqlite wagtail_localize_git.tests.test_git.TestRepository` +or, you can run them for a specific environment `tox -e py3.11-django4.2-wagtail5.2` or specific test +`tox -e py3.11-django4.2-wagtail5.2-sqlite -- tests.test_git.TestRepository` To run the test app interactively, use `tox -e interactive`, visit `http://127.0.0.1:8020/admin/` and log in with `admin`/`changeme`. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..987f622 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,96 @@ +[project] +name = "wagtail-localize-git" +description = "Wagtail Localize integration for Git-based translation services" +authors = [{name = "Karl Hobley", email = "karl@torchbox.com"}] +maintainers = [{name = "Dan Braghis", email="dan.braghis@torchbox.com"}] +readme = "README.md" +license = {file = "LICENSE"} +keywords = ["Wagtail", "Django", "content", "review"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Framework :: Django", + "Framework :: Django :: 3.2", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", + "Framework :: Wagtail", + "Framework :: Wagtail :: 5", +] + +dynamic = ["version"] +requires-python = ">=3.8" +dependencies = [ + "Django>=3.2,<5.1", + "Wagtail>=5.2", + "wagtail-localize>=1.0", + "pygit2>=1.0,<2.0", + "gitpython>=3.0,<4.0", + "toml>=0.10,<0.11", +] + +[project.optional-dependencies] +testing = [ + "dj-database-url>=2.1.0,<3.0", + "freezegun>=1.4.0,<2.0", + "coverage>=7.0,<8.0", +] + +[project.urls] +Source = "https://github.com/wagtail/wagtail-localize-git" +Changelog = "https://github.com/wagtail/wagtail-localize-git/blob/main/CHANGELOG.md" + + +[build-system] +requires = ["flit_core >=3.2,<4"] +build-backend = "flit_core.buildapi" + +[tool.flit.module] +name = "wagtail_localize_git" + +[tool.flit.sdist] +exclude = [ + ".*", + "*.db", + "*.json", + "*.ini", + "*.yaml", + "tests", + "CHANGELOG.md", + "testmanage.py", +] + +[tool.ruff] +target-version = "py38" + +select = [ + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "DJ", # flake8-django + "E", # pycodestyle errors + "F", # pyflakes + "I", # isort + "PGH", # pygrep-hooks + "S", # flake8-bandit + "SIM", # flake8-simplify + "W", # pycodestyle warnings + "YTT", # flake8-2020 + "UP", # pyupgrade + "RUF100", # unused noqa +] + +ignore = ["E501"] +fixable = ["C4", "E", "F", "I", "UP"] + +[tool.ruff.isort] +known-first-party = ["src", "wagtail_localize_git"] +lines-between-types = 1 +lines-after-imports = 2 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 5678d7f..0000000 --- a/setup.cfg +++ /dev/null @@ -1,12 +0,0 @@ -[flake8] -max-line-length=88 -exclude=migrations,dist,build,venv,node_modules,.tox,venv,.venv,.git -extend-ignore = E203, E501 - -[isort] -known_first_party=wagtail_localize -skip=migrations,.git,__pycache__,LC_MESSAGES,locale,build,dist,.github,.tox,venv,.venv,node_modules -blocked_extensions=rst,html,js,svg,txt,css,scss,png,snap,tsx,sh -lines_between_types=1 -lines_after_imports=2 -profile=black diff --git a/setup.py b/setup.py deleted file mode 100644 index e56900e..0000000 --- a/setup.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -from os import path - -from setuptools import find_packages, setup - -from wagtail_localize_git import __version__ - - -# Hack to prevent "TypeError: 'NoneType' object is not callable" error -# in multiprocessing/util.py _exit_function when setup.py exits -# (see http://www.eby-sarna.com/pipermail/peak/2010-May/003357.html) -try: - import multiprocessing # noqa -except ImportError: - pass - -this_directory = path.abspath(path.dirname(__file__)) -with open(path.join(this_directory, "README.md"), encoding="utf-8") as f: - long_description = f.read() - -setup( - name="wagtail-localize-git", - version=__version__, - description="Wagtail Localize integration for Git-based translation services", - long_description=long_description, - long_description_content_type="text/markdown", - author="Karl Hobley", - author_email="karl@torchbox.com", - url="https://github.com/wagtail/wagtail-localize-git", - project_urls={ - "Changelog": "https://github.com/wagtail/wagtail-localize-git/blob/main/CHANGELOG.md", # noqa: E501 - }, - packages=find_packages(), - include_package_data=True, - license="BSD", - classifiers=[ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Framework :: Django", - "Framework :: Django :: 3.2", - "Framework :: Django :: 4.2", - "Framework :: Django :: 5.0", - "Framework :: Wagtail", - "Framework :: Wagtail :: 5", - ], - install_requires=[ - "Django>=3.2,<5.1", - "Wagtail>=5.2", - "wagtail-localize>=1.0", - "pygit2>=1.0,<2.0", - "gitpython>=3.0,<4.0", - "toml>=0.10,<0.11", - ], - extras_require={ - "testing": ["dj-database-url==0.5.0", "freezegun==1.2.2"], - }, - zip_safe=False, -) diff --git a/wagtail_localize_git/__init__.py b/src/wagtail_localize_git/__init__.py similarity index 100% rename from wagtail_localize_git/__init__.py rename to src/wagtail_localize_git/__init__.py diff --git a/wagtail_localize_git/apps.py b/src/wagtail_localize_git/apps.py similarity index 100% rename from wagtail_localize_git/apps.py rename to src/wagtail_localize_git/apps.py diff --git a/wagtail_localize_git/git.py b/src/wagtail_localize_git/git.py similarity index 100% rename from wagtail_localize_git/git.py rename to src/wagtail_localize_git/git.py diff --git a/wagtail_localize_git/importer.py b/src/wagtail_localize_git/importer.py similarity index 99% rename from wagtail_localize_git/importer.py rename to src/wagtail_localize_git/importer.py index 6863883..ec771b2 100644 --- a/wagtail_localize_git/importer.py +++ b/src/wagtail_localize_git/importer.py @@ -1,6 +1,5 @@ from django.core.exceptions import ValidationError from django.db import transaction - from wagtail_localize.models import ( MissingRelatedObjectError, StringNotUsedInContext, diff --git a/wagtail_localize_git/management/__init__.py b/src/wagtail_localize_git/management/__init__.py similarity index 100% rename from wagtail_localize_git/management/__init__.py rename to src/wagtail_localize_git/management/__init__.py diff --git a/wagtail_localize_git/management/commands/__init__.py b/src/wagtail_localize_git/management/commands/__init__.py similarity index 100% rename from wagtail_localize_git/management/commands/__init__.py rename to src/wagtail_localize_git/management/commands/__init__.py diff --git a/wagtail_localize_git/management/commands/sync_git.py b/src/wagtail_localize_git/management/commands/sync_git.py similarity index 100% rename from wagtail_localize_git/management/commands/sync_git.py rename to src/wagtail_localize_git/management/commands/sync_git.py diff --git a/wagtail_localize_git/migrations/0001_initial.py b/src/wagtail_localize_git/migrations/0001_initial.py similarity index 99% rename from wagtail_localize_git/migrations/0001_initial.py rename to src/wagtail_localize_git/migrations/0001_initial.py index 2d677b5..79962b1 100644 --- a/wagtail_localize_git/migrations/0001_initial.py +++ b/src/wagtail_localize_git/migrations/0001_initial.py @@ -1,8 +1,9 @@ # Generated by Django 3.0.8 on 2020-07-28 09:54 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models + class Migration(migrations.Migration): initial = True diff --git a/wagtail_localize_git/migrations/__init__.py b/src/wagtail_localize_git/migrations/__init__.py similarity index 100% rename from wagtail_localize_git/migrations/__init__.py rename to src/wagtail_localize_git/migrations/__init__.py diff --git a/wagtail_localize_git/models.py b/src/wagtail_localize_git/models.py similarity index 93% rename from wagtail_localize_git/models.py rename to src/wagtail_localize_git/models.py index e40a90d..7a4609f 100644 --- a/wagtail_localize_git/models.py +++ b/src/wagtail_localize_git/models.py @@ -4,7 +4,6 @@ from wagtail.images.models import AbstractImage from wagtail.models import Locale, Page from wagtail.snippets.models import get_snippet_models - from wagtail_localize.models import TranslatableObject @@ -23,6 +22,9 @@ class Resource(models.Model): class Meta: ordering = ["path"] + def __str__(self): + return f"Resource ({self.pk}: {str(self.object)})" + @classmethod def get_for_object(cls, object): try: @@ -81,6 +83,12 @@ class SyncLog(models.Model): time = models.DateTimeField(auto_now_add=True) commit_id = models.CharField(max_length=40, blank=True) + class Meta: + ordering = ["time"] + + def __str__(self): + return f"SyncLog ({self.pk}: {self.action} - {self.time} - {self.commit_id})" + def add_translation(self, translation): SyncLogResource.objects.create( log=self, @@ -89,9 +97,6 @@ def add_translation(self, translation): source_id=translation.source_id, ) - class Meta: - ordering = ["time"] - class SyncLogResourceQuerySet(models.QuerySet): def unique_resources(self): @@ -133,3 +138,6 @@ class SyncLogResource(models.Model): class Meta: ordering = ["log__time", "resource__path"] + + def __str__(self): + return f"SyncLogResource ({self.pk}: {self.log_id}, {self.resource_id}, {self.locale_id})" diff --git a/wagtail_localize_git/sync.py b/src/wagtail_localize_git/sync.py similarity index 99% rename from wagtail_localize_git/sync.py rename to src/wagtail_localize_git/sync.py index 6c61277..b2f9465 100644 --- a/wagtail_localize_git/sync.py +++ b/src/wagtail_localize_git/sync.py @@ -9,7 +9,6 @@ from django.db import transaction from django.utils.module_loading import import_string from wagtail.models import Locale - from wagtail_localize.models import Translation from .git import Repository diff --git a/wagtail_localize_git/templates/wagtail_localize_git/dashboard.html b/src/wagtail_localize_git/templates/wagtail_localize_git/dashboard.html similarity index 100% rename from wagtail_localize_git/templates/wagtail_localize_git/dashboard.html rename to src/wagtail_localize_git/templates/wagtail_localize_git/dashboard.html diff --git a/wagtail_localize_git/views.py b/src/wagtail_localize_git/views.py similarity index 99% rename from wagtail_localize_git/views.py rename to src/wagtail_localize_git/views.py index a3de89f..702ff97 100644 --- a/wagtail_localize_git/views.py +++ b/src/wagtail_localize_git/views.py @@ -1,6 +1,5 @@ from django.contrib.auth.decorators import user_passes_test from django.shortcuts import redirect, render - from wagtail_localize.models import Translation from .models import Resource, SyncLog, SyncLogResource diff --git a/wagtail_localize_git/wagtail_hooks.py b/src/wagtail_localize_git/wagtail_hooks.py similarity index 100% rename from wagtail_localize_git/wagtail_hooks.py rename to src/wagtail_localize_git/wagtail_hooks.py diff --git a/wagtail_localize_git/test/__init__.py b/tests/__init__.py similarity index 100% rename from wagtail_localize_git/test/__init__.py rename to tests/__init__.py diff --git a/testmanage.py b/tests/manage.py similarity index 95% rename from testmanage.py rename to tests/manage.py index 7c69391..3185fb0 100644 --- a/testmanage.py +++ b/tests/manage.py @@ -9,7 +9,8 @@ from django.core.management import execute_from_command_line -os.environ["DJANGO_SETTINGS_MODULE"] = "wagtail_localize_git.test.settings" +os.environ["DJANGO_SETTINGS_MODULE"] = "testapp.settings" +sys.path.append("tests") def make_parser(): diff --git a/wagtail_localize_git/tests/test_git.py b/tests/test_git.py similarity index 100% rename from wagtail_localize_git/tests/test_git.py rename to tests/test_git.py diff --git a/wagtail_localize_git/tests/test_importer.py b/tests/test_importer.py similarity index 99% rename from wagtail_localize_git/tests/test_importer.py rename to tests/test_importer.py index 51ed644..f402912 100644 --- a/wagtail_localize_git/tests/test_importer.py +++ b/tests/test_importer.py @@ -7,16 +7,16 @@ from django.core.exceptions import ValidationError from django.test import TestCase from django.utils import timezone +from testapp.models import TestPage from wagtail.models import Locale, Page - from wagtail_localize.models import ( MissingRelatedObjectError, Translation, TranslationSource, ) + from wagtail_localize_git.importer import Importer from wagtail_localize_git.models import Resource, SyncLog -from wagtail_localize_git.test.models import TestPage def create_test_page(**kwargs): diff --git a/wagtail_localize_git/tests/test_models.py b/tests/test_models.py similarity index 97% rename from wagtail_localize_git/tests/test_models.py rename to tests/test_models.py index cb2a671..3bd9b22 100644 --- a/wagtail_localize_git/tests/test_models.py +++ b/tests/test_models.py @@ -1,12 +1,12 @@ from django.test import TestCase +from testapp.models import TestPage, TestSnippet from wagtail.documents.models import Document from wagtail.images.models import Image from wagtail.images.tests.utils import get_test_image_file from wagtail.models import Page, Site - from wagtail_localize.models import TranslationSource + from wagtail_localize_git.models import Resource -from wagtail_localize_git.test.models import TestPage, TestSnippet def create_test_page(**kwargs): diff --git a/wagtail_localize_git/tests/test_sync.py b/tests/test_sync.py similarity index 97% rename from wagtail_localize_git/tests/test_sync.py rename to tests/test_sync.py index 5437c72..a54416b 100644 --- a/wagtail_localize_git/tests/test_sync.py +++ b/tests/test_sync.py @@ -1,4 +1,3 @@ -import sys import unittest from pathlib import PurePosixPath @@ -7,12 +6,12 @@ import pygit2 from django.test import TestCase, override_settings +from testapp.models import TestPage from wagtail.models import Locale, Page - from wagtail_localize.models import StringTranslation, Translation, TranslationSource + from wagtail_localize_git.models import Resource, SyncLog from wagtail_localize_git.sync import SyncPushError, _pull, _push, get_sync_manager -from wagtail_localize_git.test.models import TestPage from .utils import GitRepositoryUtils @@ -276,13 +275,12 @@ def test_push_something(self): # Check that the source and translation files were written # Build a dictionary of calls to RepositoryWriter.write_file(). Keyed by first argument (filename) # Note, this check only works on Python 3.8+ - if sys.version_info >= (3, 8): - mock_calls = { - call.args[0]: call for call in repo.writer().write_file.mock_calls - } + mock_calls = { + call.args[0]: call for call in repo.writer().write_file.mock_calls + } - self.assertIn("templates/pages/test-page.pot", mock_calls.keys()) - self.assertIn("locales/fr/pages/test-page.po", mock_calls.keys()) + self.assertIn("templates/pages/test-page.pot", mock_calls.keys()) + self.assertIn("locales/fr/pages/test-page.po", mock_calls.keys()) # Check that the repo was pushed repo.push.assert_called_once() diff --git a/wagtail_localize_git/tests/test_views.py b/tests/test_views.py similarity index 98% rename from wagtail_localize_git/tests/test_views.py rename to tests/test_views.py index a0d0fb9..a770e69 100644 --- a/wagtail_localize_git/tests/test_views.py +++ b/tests/test_views.py @@ -4,12 +4,12 @@ from django.contrib.auth.models import Group from django.test import TestCase from django.urls import reverse +from testapp.models import TestPage from wagtail.models import Locale, Page from wagtail.test.utils import WagtailTestUtils - from wagtail_localize.models import Translation, TranslationSource + from wagtail_localize_git.models import Resource, SyncLog, SyncLogResource -from wagtail_localize_git.test.models import TestPage def create_test_page(**kwargs): diff --git a/wagtail_localize_git/test/migrations/__init__.py b/tests/testapp/__init__.py similarity index 100% rename from wagtail_localize_git/test/migrations/__init__.py rename to tests/testapp/__init__.py diff --git a/wagtail_localize_git/test/apps.py b/tests/testapp/apps.py similarity index 84% rename from wagtail_localize_git/test/apps.py rename to tests/testapp/apps.py index 909265a..7058e55 100644 --- a/wagtail_localize_git/test/apps.py +++ b/tests/testapp/apps.py @@ -3,6 +3,6 @@ class WagtailLocalizeGitTestAppConfig(AppConfig): label = "wagtail_localize_git_test" - name = "wagtail_localize_git.test" + name = "testapp" verbose_name = "Localize Git tests" default_auto_field = "django.db.models.AutoField" diff --git a/wagtail_localize_git/test/migrations/0001_initial.py b/tests/testapp/migrations/0001_initial.py similarity index 98% rename from wagtail_localize_git/test/migrations/0001_initial.py rename to tests/testapp/migrations/0001_initial.py index 8a8c13b..4001876 100644 --- a/wagtail_localize_git/test/migrations/0001_initial.py +++ b/tests/testapp/migrations/0001_initial.py @@ -1,10 +1,12 @@ # Generated by Django 4.1.1 on 2022-09-19 19:41 -from django.db import migrations, models -import django.db.models.deletion import uuid + +import django.db.models.deletion import wagtail.fields as wagtail_fields +from django.db import migrations, models + class Migration(migrations.Migration): initial = True @@ -34,7 +36,6 @@ class Migration(migrations.Migration): blank=True, default="", max_length=255, - null=True, verbose_name="char field", ), ), diff --git a/wagtail_localize_git/tests/__init__.py b/tests/testapp/migrations/__init__.py similarity index 100% rename from wagtail_localize_git/tests/__init__.py rename to tests/testapp/migrations/__init__.py diff --git a/wagtail_localize_git/test/models.py b/tests/testapp/models.py similarity index 98% rename from wagtail_localize_git/test/models.py rename to tests/testapp/models.py index b9c6066..0be5ce8 100644 --- a/wagtail_localize_git/test/models.py +++ b/tests/testapp/models.py @@ -5,13 +5,12 @@ from wagtail.fields import RichTextField from wagtail.models import Page, TranslatableMixin from wagtail.snippets.models import register_snippet - from wagtail_localize.fields import SynchronizedField, TranslatableField class TestPage(Page): test_charfield = models.CharField( - gettext_lazy("char field"), max_length=255, blank=True, null=True, default="" + gettext_lazy("char field"), max_length=255, blank=True, default="" ) test_textfield = models.TextField(blank=True) test_richtextfield = RichTextField(blank=True) diff --git a/wagtail_localize_git/test/settings.py b/tests/testapp/settings.py similarity index 90% rename from wagtail_localize_git/test/settings.py rename to tests/testapp/settings.py index a8dbea3..c815ef2 100644 --- a/wagtail_localize_git/test/settings.py +++ b/tests/testapp/settings.py @@ -23,7 +23,7 @@ # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "c6u0-9c!7nilj_ysatsda0(f@e_2mws2f!6m0n^o*4#*q#kzp)" +SECRET_KEY = "not-a-secret" # noqa: S105 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -35,26 +35,16 @@ INSTALLED_APPS = [ "wagtail_localize_git", - "wagtail_localize_git.test", + "testapp", "wagtail_localize", - "wagtail.contrib.search_promotions", - "wagtail.contrib.forms", - "wagtail.contrib.redirects", - "wagtail.embeds", "wagtail.users", "wagtail.snippets", "wagtail.documents", "wagtail.images", - "wagtail.search", "wagtail.admin", - "wagtail.api.v2", - "wagtail.contrib.modeladmin", - "wagtail.contrib.routable_page", - "wagtail.contrib.styleguide", "wagtail.sites", "wagtail", "taggit", - "rest_framework", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", @@ -75,7 +65,7 @@ "wagtail.contrib.redirects.middleware.RedirectMiddleware", ] -ROOT_URLCONF = "wagtail_localize_git.test.urls" +ROOT_URLCONF = "testapp.urls" TEMPLATES = [ { diff --git a/wagtail_localize_git/test/urls.py b/tests/testapp/urls.py similarity index 100% rename from wagtail_localize_git/test/urls.py rename to tests/testapp/urls.py diff --git a/wagtail_localize_git/tests/utils.py b/tests/utils.py similarity index 100% rename from wagtail_localize_git/tests/utils.py rename to tests/utils.py diff --git a/tox.ini b/tox.ini index 459b153..b3246d2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,28 +1,38 @@ [tox] -skipsdist = True -usedevelop = True +min_version = 4.0 -requires = tox >= 3.23.0, < 4.0 - tox-py >= 1.1.0 - -# note: use py and non-dotted python version as we use tox-py envlist = - python{3.8,3.9,3.10}-django{3.2}-wagtail{5.2} - python{3.8,3.9,3.10,3.11,3.12}-django{4.2}-wagtail{5.2} - python{3.10,3.11,3.12}-django{5.0}-wagtail{5.2} + py{3.8,3.9,3.10}-django{3.2}-wagtail{5.2} + py{3.8,3.9,3.10,3.11,3.12}-django{4.2}-wagtail{5.2} + py{3.10,3.11,3.12}-django{5.0}-wagtail{5.2} + +[gh-actions] +python = + 3.8: py38 + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 -[flake8] -# E501: Line too long -# W503: line break before binary operator (superseded by W504 line break after binary operator) -ignore = E501,W503 -exclude = migrations,node_modules +[gh-actions:env] +DB = + sqlite: sqlite + postgres: postgres [testenv] -install_command = pip install -U --pre {opts} {packages} -e ".[testing]" -commands = coverage run testmanage.py test --deprecation all {posargs: -v 2} +package = wheel +wheel_build_env = .pkg + +pass_env = + FORCE_COLOR + NO_COLOR + +setenv = + PYTHONPATH = {toxinidir}/tests:{toxinidir} + PYTHONDEVMODE = 1 deps = - coverage + flit>=3.8 django3.2: Django>=3.2,<3.3 django4.2: Django>=4.2,<4.3 @@ -32,25 +42,39 @@ deps = wagtail5.2: wagtail>=5.2,<5.3 wagtailmain: git+https://github.com/wagtail/wagtail.git - postgres: psycopg2>=2.6 + postgres: psycopg2>=2.9 -[testenv:flake8] -basepython=python3.11 -deps=flake8>=2.2.0 -commands=flake8 wagtail_localize_git + .[testing] +install_command = python -Im pip install -U --pre {opts} {packages} +commands_pre = + python -I {toxinidir}/tests/manage.py migrate +commands = + python -m coverage run {toxinidir}/tests/manage.py test --deprecation all {posargs: -v 2} + +[testenv:coverage-report] +commands = + python -Im coverage combine + python -Im coverage report -m [testenv:interactive] +description = An interactive environment for local testing purposes basepython = python3.11 commands_pre = - python {toxinidir}/testmanage.py makemigrations - python {toxinidir}/testmanage.py migrate - python {toxinidir}/testmanage.py shell -c "from django.contrib.auth.models import User;(not User.objects.filter(username='admin').exists()) and User.objects.create_superuser('admin', 'super@example.com', 'changeme')" - python {toxinidir}/testmanage.py createcachetable + python {toxinidir}/tests/manage.py makemigrations + python {toxinidir}/tests/manage.py migrate + python {toxinidir}/tests/manage.py shell -c "from django.contrib.auth.models import User;(not User.objects.filter(username='admin').exists()) and User.objects.create_superuser('admin', 'super@example.com', 'changeme')" + python {toxinidir}/tests/manage.py createcachetable commands = - {posargs:python testmanage.py runserver 0.0.0.0:8020} + {posargs:python -Im {toxinidir}/tests/manage.py runserver 0.0.0.0:8020} setenv = INTERACTIVE = 1 + +[testenv:wagtailmain] +deps = + flit>=3.8 + coverage>=7.0,<8.0 + wagtailmain: git+https://github.com/wagtail/wagtail.git@main#egg=Wagtail