From 84d0eae52668051bed42dc8ea1d74c59833c9f13 Mon Sep 17 00:00:00 2001 From: Alexandra Bruckner Date: Fri, 20 Oct 2023 14:47:44 +0200 Subject: [PATCH] Add github workflow actions (test, publish) --- .github/workflows/publish.yml | 41 +++++++++++++ .github/workflows/test.yml | 53 +++++++++++++++++ README.md | 4 ++ django_generic_contact/admin.py | 1 + .../migrations/0001_initial.py | 18 +++++- .../migrations/0002_alter_contact_message.py | 1 - django_generic_contact/models.py | 2 - django_generic_contact/utils.py | 5 +- django_generic_contact/validators.py | 4 +- tests/testapp/tests/test_model.py | 58 ++++++++++--------- tests/testapp/tests/test_setup.py | 3 +- 11 files changed, 154 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..aba4195 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,41 @@ +name: Publish package +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.10' + architecture: 'x64' + + - name: Install dependencies and package + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Build source and binary distribution package + run: | + python setup.py sdist bdist_wheel + env: + PACKAGE_VERSION: ${{ github.ref }} + + - name: Check distribution package + run: | + twine check dist/* + + - name: Publish distribution package + run: | + twine upload dist/* + env: + TWINE_REPOSITORY: ${{ secrets.PYPI_REPOSITORY }} + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + TWINE_NON_INTERACTIVE: yes \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..7b64b6c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,53 @@ +name: Run linter and tests +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + django-version: + - '3.2' + - '4.1' + - '4.2' + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies and package + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install django~=${{ matrix.django-version }}.0 + + - name: Run lint and code review with isort and black + run: | + pre-commit run --all-files + + - name: Run tests with coverage + run: | + # prepare Django project: link all necessary data from the test project into the root directory + # Hint: Simply changing the directory does not work (leads to missing files in coverage report) + ln -s ./tests/core core + ln -s ./tests/testapp testapp + ln -s ./tests/manage.py manage.py + + # run tests with coverage + coverage run \ + --source='./django_generic_contact' \ + manage.py test + coverage xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 \ No newline at end of file diff --git a/README.md b/README.md index 0197aac..2171e64 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ ## Django Generic Contact +[![PyPI version](https://img.shields.io/pypi/v/django-generic-contact.svg)](https://pypi.org/project/django-generic-contact/) +[![Run linter and tests](https://github.com/anexia/django-generic-contact/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/anexia/django-generic-contact/actions/workflows/test.yml) +[![Codecov](https://img.shields.io/codecov/c/gh/anexia/django-generic-contact)](https://codecov.io/gh/anexia/django-generic-contact) + Django module to store contact request in a structured yet generic manner within the database. ### Installation diff --git a/django_generic_contact/admin.py b/django_generic_contact/admin.py index e0ae205..62dfdd4 100644 --- a/django_generic_contact/admin.py +++ b/django_generic_contact/admin.py @@ -1,5 +1,6 @@ from django import forms from django.contrib import admin + from django_generic_contact.models import Contact from django_generic_contact.utils import get_help_text, get_validators diff --git a/django_generic_contact/migrations/0001_initial.py b/django_generic_contact/migrations/0001_initial.py index 2bbedeb..f733f4e 100644 --- a/django_generic_contact/migrations/0001_initial.py +++ b/django_generic_contact/migrations/0001_initial.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [] @@ -13,8 +12,21 @@ class Migration(migrations.Migration): migrations.CreateModel( name="Contact", fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("creation_date", models.DateTimeField(auto_now_add=True, verbose_name="Creation date")), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "creation_date", + models.DateTimeField( + auto_now_add=True, verbose_name="Creation date" + ), + ), ("data", models.JSONField(default=dict, verbose_name="meta data")), ("name", models.CharField(max_length=255, verbose_name="name")), ("message", models.TextField(verbose_name="message")), diff --git a/django_generic_contact/migrations/0002_alter_contact_message.py b/django_generic_contact/migrations/0002_alter_contact_message.py index b2dbf31..d3eece9 100644 --- a/django_generic_contact/migrations/0002_alter_contact_message.py +++ b/django_generic_contact/migrations/0002_alter_contact_message.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("django_generic_contact", "0001_initial"), ] diff --git a/django_generic_contact/models.py b/django_generic_contact/models.py index 4cea1da..94d4b62 100644 --- a/django_generic_contact/models.py +++ b/django_generic_contact/models.py @@ -6,7 +6,6 @@ class GenericContact(models.Model): - creation_date = models.DateTimeField( verbose_name=_("Creation date"), blank=False, @@ -24,7 +23,6 @@ class Meta: class Contact(GenericContact): - name = models.CharField(_("name"), max_length=255) message = models.TextField(_("message"), blank=True) diff --git a/django_generic_contact/utils.py b/django_generic_contact/utils.py index f9f0ebd..e9a5019 100644 --- a/django_generic_contact/utils.py +++ b/django_generic_contact/utils.py @@ -1,10 +1,13 @@ from django.utils.translation import gettext_lazy as _ + from django_generic_contact.models import GENERIC_CONTACT_DATA_SCHEMA from django_generic_contact.validators import JSONSchemaValidator def get_help_text(): - return _("Meta data according to Schema: {schema}").format(schema=GENERIC_CONTACT_DATA_SCHEMA) + return _("Meta data according to Schema: {schema}").format( + schema=GENERIC_CONTACT_DATA_SCHEMA + ) def get_validators(): diff --git a/django_generic_contact/validators.py b/django_generic_contact/validators.py index e8b290f..227c84a 100644 --- a/django_generic_contact/validators.py +++ b/django_generic_contact/validators.py @@ -6,6 +6,8 @@ class JSONSchemaValidator(BaseValidator): def compare(self, value, schema): try: - jsonschema.validate(value, schema, format_checker=jsonschema.draft202012_format_checker) + jsonschema.validate( + value, schema, format_checker=jsonschema.draft202012_format_checker + ) except jsonschema.exceptions.ValidationError as e: raise ValidationError(str(e)) diff --git a/tests/testapp/tests/test_model.py b/tests/testapp/tests/test_model.py index 9fc180b..ea9d7d6 100644 --- a/tests/testapp/tests/test_model.py +++ b/tests/testapp/tests/test_model.py @@ -1,7 +1,7 @@ from django.core.exceptions import ValidationError from django.test import TestCase -from django_generic_contact.models import Contact, GENERIC_CONTACT_DATA_SCHEMA +from django_generic_contact.models import GENERIC_CONTACT_DATA_SCHEMA, Contact from django_generic_contact.validators import JSONSchemaValidator @@ -13,7 +13,7 @@ def test_successful_contact_creation(self): data={ "email": "mr@tester.com", "phone": "123456", - } + }, ) self.assertEqual(Contact.objects.count(), 1) @@ -22,25 +22,29 @@ def test_successful_contact_creation(self): class TestJsonSchema(TestCase): def test_successful_jsonschema_validation(self): validator = JSONSchemaValidator(limit_value=GENERIC_CONTACT_DATA_SCHEMA) - validator({ - "email": "mr@tester.com", - "not_validated_phone": "+431234567", - }) + validator( + { + "email": "mr@tester.com", + "not_validated_phone": "+431234567", + } + ) def test_failed_jsonschema_validation_invalid_email(self): validator = JSONSchemaValidator(limit_value=GENERIC_CONTACT_DATA_SCHEMA) with self.assertRaises( - ValidationError, - msg="'invalid_email' is not a 'email'\n\n" - "Failed validating 'format' in schema['properties']['email']:\n" - " {'format': 'email', 'type': 'string'}\n\n" - "On instance['email']:\n" - " 'invalid_email'" + ValidationError, + msg="'invalid_email' is not a 'email'\n\n" + "Failed validating 'format' in schema['properties']['email']:\n" + " {'format': 'email', 'type': 'string'}\n\n" + "On instance['email']:\n" + " 'invalid_email'", ): - validator({ - "email": "invalid_email", - "not_validated_phone": "+431234567", - }) + validator( + { + "email": "invalid_email", + "not_validated_phone": "+431234567", + } + ) def test_failed_jsonschema_validation_additional_fields(self): test_schema = { @@ -53,14 +57,16 @@ def test_failed_jsonschema_validation_additional_fields(self): } validator = JSONSchemaValidator(limit_value=test_schema) with self.assertRaises( - ValidationError, - msg="'+431234567' is not of type 'integer'\n\n" - "Failed validating 'type' in schema['properties']['phone']:\n" - " {'type': 'integer'}\n\n" - "On instance['phone']:\n" - " '+431234567'" + ValidationError, + msg="'+431234567' is not of type 'integer'\n\n" + "Failed validating 'type' in schema['properties']['phone']:\n" + " {'type': 'integer'}\n\n" + "On instance['phone']:\n" + " '+431234567'", ): - validator({ - "email": "mr@tester.com", - "phone": "+431234567", - }) + validator( + { + "email": "mr@tester.com", + "phone": "+431234567", + } + ) diff --git a/tests/testapp/tests/test_setup.py b/tests/testapp/tests/test_setup.py index 18ea781..ab234b7 100644 --- a/tests/testapp/tests/test_setup.py +++ b/tests/testapp/tests/test_setup.py @@ -1,6 +1,5 @@ -from django.test import SimpleTestCase - from django.conf import settings +from django.test import SimpleTestCase class TestSetup(SimpleTestCase):