diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f81b1fb1..f33ea1df2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,31 +10,80 @@ jobs: max-parallel: 4 matrix: python-version: ['3.10'] + node-version: ['18'] steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.10 + - uses: actions/checkout@v3 + - uses: awalsh128/cache-apt-pkgs-action@v1.3.1 + with: + packages: libsasl2-dev python3-dev libldap2-dev libssl-dev + version: 1.0 + + # Setup python & dependencies + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: - python-version: '3.10' - # Build Vue frontend - - uses: actions/setup-node@v4 - with: - node-version: '18' - - name: Install Vue dependencies - working-directory: ./vue - run: yarn install - - name: Build Vue dependencies - working-directory: ./vue - run: yarn build - - name: Install Django dependencies + python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Install Python Dependencies run: | - sudo apt-get -y update - sudo apt-get install -y libsasl2-dev python3-dev libldap2-dev libssl-dev python -m pip install --upgrade pip pip install -r requirements.txt + + - name: Cache StaticFiles + uses: actions/cache@v3 + id: django_cache + with: + path: | + ./cookbook/static + ./vue/webpack-stats.json + ./staticfiles + key: | + ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.node-version }}-collectstatic-${{ hashFiles('**/*.css', '**/*.js', 'vue/src/*') }} + + # Build Vue frontend & Dependencies + - name: Set up Node ${{ matrix.node-version }} + if: steps.django_cache.outputs.cache-hit != 'true' + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'yarn' + cache-dependency-path: ./vue/yarn.lock + + - name: Install Vue dependencies + if: steps.django_cache.outputs.cache-hit != 'true' + working-directory: ./vue + run: yarn install + + - name: Build Vue dependencies + if: steps.django_cache.outputs.cache-hit != 'true' + working-directory: ./vue + run: yarn build + + - name: Compile Django StatisFiles + if: steps.django_cache.outputs.cache-hit != 'true' + run: | python3 manage.py collectstatic --noinput python3 manage.py collectstatic_js_reverse + + - uses: actions/cache/save@v3 + if: steps.django_cache.outputs.cache-hit != 'true' + with: + path: | + ./cookbook/static + ./vue/webpack-stats.json + ./staticfiles + key: | + ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.node-version }}-collectstatic-${{ hashFiles('**/*.css', '**/*.js', 'vue/src/*') }} + - name: Django Testing project - run: | - pytest + run: pytest --junitxml=junit/test-results-${{ matrix.python-version }}.xml + + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + comment_mode: off + files: | + junit/test-results-${{ matrix.python-version }}.xml diff --git a/cookbook/admin.py b/cookbook/admin.py index 823246283..fc148afe5 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -315,8 +315,8 @@ admin.site.register(MealPlan, MealPlanAdmin) class MealTypeAdmin(admin.ModelAdmin): - list_display = ('name', 'created_by', 'order') - search_fields = ('name', 'created_by__username') + list_display = ('name', 'space', 'created_by', 'order') + search_fields = ('name', 'space', 'created_by__username') admin.site.register(MealType, MealTypeAdmin) diff --git a/cookbook/management/commands/seed_basic_data.py b/cookbook/management/commands/seed_basic_data.py new file mode 100644 index 000000000..25e5ef98f --- /dev/null +++ b/cookbook/management/commands/seed_basic_data.py @@ -0,0 +1,25 @@ +from django.conf import settings +from django.contrib.auth.models import User +from django.contrib.postgres.search import SearchVector +from django.core.management.base import BaseCommand +from django.utils import translation +from django.utils.translation import gettext_lazy as _ +from django_scopes import scopes_disabled + +from cookbook.managers import DICTIONARY +from cookbook.models import Recipe, Step, Space + + +class Command(BaseCommand): + help = 'Seeds some basic data (space, account, food)' + + def handle(self, *args, **options): + with scopes_disabled(): + user = User.objects.get_or_create(username='test')[0] + user.set_password('test') + user.save() + + space = Space.objects.get_or_create( + name='Test Space', + created_by=user + )[0] diff --git a/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py b/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py index a57ad9773..03f7aa6d6 100644 --- a/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py +++ b/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py @@ -13,22 +13,22 @@ def migrate_icons(apps, schema_editor): PropertyType = apps.get_model('cookbook', 'PropertyType') RecipeBook = apps.get_model('cookbook', 'RecipeBook') - duplicate_meal_types = MealType.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = MealType.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate MealTypes found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') MealType.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) - duplicate_meal_types = Keyword.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = Keyword.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate Keyword found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') Keyword.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) - duplicate_meal_types = PropertyType.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = PropertyType.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate PropertyType found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') PropertyType.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) - duplicate_meal_types = RecipeBook.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = RecipeBook.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate RecipeBook found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') RecipeBook.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) @@ -40,7 +40,7 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython( migrate_icons), + migrations.RunPython(migrate_icons), migrations.AlterModelOptions( name='propertytype', options={'ordering': ('order',)}, diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 609ade4cb..4c7e2dfb8 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -353,8 +353,7 @@ class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer): validated_data['name'] = validated_data['name'].strip() space = validated_data.pop('space', self.context['request'].space) validated_data['created_by'] = self.context['request'].user - obj, created = MealType.objects.get_or_create(name__iexact=validated_data['name'], space=space, - defaults=validated_data) + obj, created = MealType.objects.get_or_create(name__iexact=validated_data['name'], space=space, created_by=self.context['request'].user, defaults=validated_data) return obj class Meta: diff --git a/docs/install/docker/ipv6_plain/docker-compose.yml b/docs/install/docker/ipv6_plain/docker-compose.yml index 312b14000..e989fc09c 100644 --- a/docs/install/docker/ipv6_plain/docker-compose.yml +++ b/docs/install/docker/ipv6_plain/docker-compose.yml @@ -2,7 +2,7 @@ version: "2.4" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ${POSTGRES_DATA_DIR:-./postgresql}:/var/lib/postgresql/data env_file: diff --git a/docs/install/docker/nginx-proxy/docker-compose.yml b/docs/install/docker/nginx-proxy/docker-compose.yml index 7040c566b..2e408646d 100644 --- a/docs/install/docker/nginx-proxy/docker-compose.yml +++ b/docs/install/docker/nginx-proxy/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/docs/install/docker/plain/docker-compose.yml b/docs/install/docker/plain/docker-compose.yml index 203217e40..089e72c56 100644 --- a/docs/install/docker/plain/docker-compose.yml +++ b/docs/install/docker/plain/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/docs/install/docker/traefik-nginx/docker-compose.yml b/docs/install/docker/traefik-nginx/docker-compose.yml index 9947c3a80..afe2fbfb7 100644 --- a/docs/install/docker/traefik-nginx/docker-compose.yml +++ b/docs/install/docker/traefik-nginx/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/docs/install/swag.md b/docs/install/swag.md index 3f1eda6a1..15b2b9b65 100644 --- a/docs/install/swag.md +++ b/docs/install/swag.md @@ -69,7 +69,7 @@ services: db_recipes: restart: always container_name: db_recipes - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./recipes/db:/var/lib/postgresql/data env_file: diff --git a/docs/install/truenas_portainer.md b/docs/install/truenas_portainer.md index 7be57bf2a..436fc5952 100644 --- a/docs/install/truenas_portainer.md +++ b/docs/install/truenas_portainer.md @@ -81,7 +81,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: