This commit is contained in:
Lucie Daeye 2020-04-16 15:44:02 +02:00
Родитель 4798be00ba
Коммит 9bab6bb391
9 изменённых файлов: 348 добавлений и 269 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -91,6 +91,7 @@ celerybeat-schedule
# virtualenv
venv/
ENV/
dockerpythonvenv/
# Spyder project settings
.spyderproject
@ -123,4 +124,4 @@ cypress/screenshots
# Translations
translations.tar
translations_github_commit_*
translations_github_commit_*

4
dev-requirements.in Normal file
Просмотреть файл

@ -0,0 +1,4 @@
-c requirements.txt
flake8
coveralls
black

27
dev-requirements.txt Normal file
Просмотреть файл

@ -0,0 +1,27 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile dev-requirements.in
#
appdirs==1.4.3 # via black
attrs==19.3.0 # via black
black==19.10b0 # via -r dev-requirements.in
certifi==2020.4.5.1 # via -c requirements.txt, requests
chardet==3.0.4 # via -c requirements.txt, requests
click==7.1.1 # via black
coverage==5.1 # via coveralls
coveralls==2.0.0 # via -r dev-requirements.in
docopt==0.6.2 # via coveralls
entrypoints==0.3 # via flake8
flake8==3.7.9 # via -r dev-requirements.in
idna==2.9 # via -c requirements.txt, requests
mccabe==0.6.1 # via flake8
pathspec==0.8.0 # via black
pycodestyle==2.5.0 # via flake8
pyflakes==2.1.1 # via flake8
regex==2020.4.4 # via black
requests==2.23.0 # via -c requirements.txt, coveralls
toml==0.10.0 # via black
typed-ast==1.4.1 # via black
urllib3==1.25.8 # via -c requirements.txt, requests

Просмотреть файл

@ -16,7 +16,6 @@ services:
command: npm run watch
volumes:
- .:/app:delegated
- node_dependencies:/app/node_modules/:delegated
postgres:
image: postgres:9.6
@ -35,7 +34,7 @@ services:
dockerfile: ./dockerfiles/Dockerfile.python
env_file:
- ".env"
command: pipenv run python network-api/manage.py runserver 0.0.0.0:8000
command: dockerpythonvenv/bin/python network-api/manage.py runserver 0.0.0.0:8000
ports:
- "8000:8000"
volumes:
@ -46,4 +45,3 @@ services:
volumes:
postgres_data:
node_dependencies:

Просмотреть файл

@ -1,8 +1,3 @@
FROM node:12-stretch-slim
FROM node:12.16.2-stretch-slim
WORKDIR /app/
# Copy package files in the container
COPY package.json package-lock.json ./
RUN npm install

Просмотреть файл

@ -1,4 +1,4 @@
FROM python:3.7-slim
FROM python:3.7.7-slim
RUN apt-get update && apt-get install -y \
gettext \
@ -10,12 +10,3 @@ ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
WORKDIR /app/
# Install pipenv
RUN pip install pipenv
# Copy Pipfiles in the container
COPY Pipfile* ./
# Install app deps
RUN pipenv install -d

29
requirements.in Normal file
Просмотреть файл

@ -0,0 +1,29 @@
beautifulsoup4
boto3
Django==2.2.11
dj-database-url
djangorestframework
django-admin-sortable==2.2.3
django-cors-headers
django_csp
django-environ
django-filter
django-redis
django-storages
Faker
filebrowser-safe
future
gunicorn
python-slugify
requests
social-auth-app-django
wagtail
wagtail-factories
wagtail-inventory
wagtail-metadata
whitenoise
wagtail-modeltranslation
psycopg2-binary
cloudinary
wagtail-experiments
sentry-sdk

74
requirements.txt Normal file
Просмотреть файл

@ -0,0 +1,74 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile
#
beautifulsoup4==4.6.0 # via -r requirements.in, wagtail
boto3==1.12.39 # via -r requirements.in
botocore==1.15.39 # via boto3, s3transfer
certifi==2020.4.5.1 # via cloudinary, requests, sentry-sdk
cffi==1.14.0 # via cryptography
chardet==3.0.4 # via requests
cloudinary==1.20.0 # via -r requirements.in
cryptography==2.9 # via social-auth-core
defusedxml==0.6.0 # via python3-openid, social-auth-core
dj-database-url==0.5.0 # via -r requirements.in
django-admin-sortable==2.2.3 # via -r requirements.in
django-cors-headers==3.2.1 # via -r requirements.in
django-csp==3.6 # via -r requirements.in
django-environ==0.4.5 # via -r requirements.in
django-filter==2.2.0 # via -r requirements.in
django-modelcluster==5.0.1 # via wagtail
django-modeltranslation==0.14.4 # via wagtail-modeltranslation
django-redis==4.11.0 # via -r requirements.in
django-storages==1.9.1 # via -r requirements.in
django-taggit==1.2.0 # via wagtail
django-treebeard==4.3.1 # via wagtail
django==2.2.11 # via -r requirements.in, django-admin-sortable, django-cors-headers, django-csp, django-filter, django-modeltranslation, django-redis, django-storages, django-taggit, django-treebeard, djangorestframework, wagtail, wagtail-inventory
djangorestframework==3.11.0 # via -r requirements.in, wagtail
docutils==0.15.2 # via botocore
draftjs-exporter==2.1.7 # via wagtail
factory-boy==2.12.0 # via wagtail-factories
faker==4.0.3 # via -r requirements.in, factory-boy
filebrowser-safe==0.5.0 # via -r requirements.in
future==0.18.2 # via -r requirements.in
gunicorn==20.0.4 # via -r requirements.in
html5lib==1.0.1 # via wagtail
idna==2.9 # via requests
jmespath==0.9.5 # via boto3, botocore
l18n==2018.5 # via wagtail
oauthlib==3.1.0 # via requests-oauthlib, social-auth-core
pillow==6.2.2 # via wagtail
psycopg2-binary==2.8.5 # via -r requirements.in
pycparser==2.20 # via cffi
pyjwt==1.7.1 # via social-auth-core
python-dateutil==2.8.1 # via botocore, faker
python-slugify==4.0.0 # via -r requirements.in
python3-openid==3.1.0 # via social-auth-core
pytz==2019.3 # via django, django-modelcluster, l18n
redis==3.4.1 # via django-redis
requests-oauthlib==1.3.0 # via social-auth-core
requests==2.23.0 # via -r requirements.in, requests-oauthlib, social-auth-core, wagtail
s3transfer==0.3.3 # via boto3
sentry-sdk==0.14.3 # via -r requirements.in
six==1.14.0 # via cloudinary, cryptography, django-modeltranslation, html5lib, l18n, python-dateutil, social-auth-app-django, social-auth-core
social-auth-app-django==3.1.0 # via -r requirements.in
social-auth-core==3.3.3 # via social-auth-app-django
sqlparse==0.3.1 # via django
text-unidecode==1.3 # via faker, python-slugify
tqdm==4.15.0 # via wagtail-inventory
unidecode==1.1.1 # via wagtail
urllib3==1.25.8 # via botocore, cloudinary, requests, sentry-sdk
wagtail-experiments==0.2 # via -r requirements.in
wagtail-factories==2.0.0 # via -r requirements.in
wagtail-inventory==1.0 # via -r requirements.in
wagtail-metadata==3.0.0 # via -r requirements.in
wagtail-modeltranslation==0.10.13 # via -r requirements.in
wagtail==2.8.1 # via -r requirements.in, wagtail-factories, wagtail-inventory, wagtail-metadata, wagtail-modeltranslation
webencodings==0.5.1 # via html5lib
whitenoise==5.0.1 # via -r requirements.in
willow==1.3 # via wagtail
# The following packages are considered to be unsafe in a requirements file:
# setuptools

458
tasks.py
Просмотреть файл

@ -1,109 +1,245 @@
import os
import re
from sys import platform
from shutil import copy
from invoke import task
# Workaround for homebrew installation of Python (https://bugs.python.org/issue22490)
import os
os.environ.pop('__PYVENV_LAUNCHER__', None)
ROOT = os.path.dirname(os.path.realpath(__file__))
LOCALE_DIR = os.path.realpath(os.path.abspath('network-api/locale'))
LOCALE_DIR = os.path.realpath(os.path.abspath("network-api/locale"))
# Python commands's outputs are not rendering properly. Setting pty for *Nix system and
# "PYTHONUNBUFFERED" env var for Windows at True.
if platform == 'win32':
PLATFORM_ARG = dict(env={'PYTHONUNBUFFERED': 'True'})
if platform == "win32":
PLATFORM_ARG = dict(env={"PYTHONUNBUFFERED": "True"})
else:
PLATFORM_ARG = dict(pty=True)
# The command for locale string abstraction is long and elaborate,
# so we build it here rather so that we don't clutter up the tasks.
locale_abstraction_instructions = " ".join([
"makemessages",
"--keep-pot",
"--no-wrap",
"--ignore=network-api/networkapi/wagtailcustomization/*",
"--ignore=network-api/networkapi/wagtail_l10n_customization/*",
"--ignore=network-api/networkapi/settings.py",
"--ignore=network-api/networkapi/wagtailpages/__init__.py",
])
locale_abstraction_instructions = " ".join(
[
"makemessages",
"--keep-pot",
"--no-wrap",
"--ignore=network-api/networkapi/wagtailcustomization/*",
"--ignore=network-api/networkapi/wagtail_l10n_customization/*",
"--ignore=network-api/networkapi/settings.py",
"--ignore=network-api/networkapi/wagtailpages/__init__.py",
]
)
def create_docker_env_file(env_file):
def create_env_file(env_file):
"""Create or update an .env to work with a docker environment"""
with open(env_file, 'r') as f:
with open(env_file, "r") as f:
env_vars = f.read()
# We need to strip the quotes because Docker-compose considers them as part of the env value.
env_vars = env_vars.replace('"', '')
env_vars = env_vars.replace('"', "")
# We also need to make sure to use the correct db values based on our docker settings.
username = password = dbname = 'postgres'
with open('docker-compose.yml', 'r') as d:
username = password = dbname = "postgres"
with open("docker-compose.yml", "r") as d:
docker_compose = d.read()
username = re.search('POSTGRES_USER=(.*)', docker_compose).group(1) or username
password = re.search('POSTGRES_PASSWORD=(.*)', docker_compose).group(1) or password
dbname = re.search('POSTGRES_DB=(.*)', docker_compose).group(1) or dbname
username = re.search("POSTGRES_USER=(.*)", docker_compose).group(1) or username
password = (
re.search("POSTGRES_PASSWORD=(.*)", docker_compose).group(1) or password
)
dbname = re.search("POSTGRES_DB=(.*)", docker_compose).group(1) or dbname
# Update the DATABASE_URL env
new_db_url = f"DATABASE_URL=postgresql://{username}:{password}@postgres:5432/{dbname}"
old_db_url = re.search('DATABASE_URL=.*', env_vars)
new_db_url = (
f"DATABASE_URL=postgresql://{username}:{password}@postgres:5432/{dbname}"
)
old_db_url = re.search("DATABASE_URL=.*", env_vars)
env_vars = env_vars.replace(old_db_url.group(0), new_db_url)
# update the ALLOWED_HOSTS
new_hosts = "ALLOWED_HOSTS=*"
old_hosts = re.search('ALLOWED_HOSTS=.*', env_vars)
old_hosts = re.search("ALLOWED_HOSTS=.*", env_vars)
env_vars = env_vars.replace(old_hosts.group(0), new_hosts)
# create the new env file
with open('.env', 'w') as f:
with open(".env", "w") as f:
f.write(env_vars)
# Tasks without Docker
# Project setup and update
def l10n_block_inventory(ctx):
print("* Updating localizable fields")
l10n_sync(ctx)
l10n_update(ctx)
print("* Updating block information")
manage(ctx, "block_inventory")
@task(optional=['option', 'flag'])
def manage(ctx, command, option=None, flag=None):
"""Shorthand to manage.py. inv manage \"[COMMAND] [ARG]\". ex: inv manage \"runserver 3000\""""
def create_super_user(ctx):
preamble = "from django.contrib.auth.models import User;"
create = "User.objects.create_superuser('admin', 'admin@example.com', 'admin')"
manage(ctx, f'shell -c "{preamble} {create}"')
print("\nCreated superuser `admin` with password `admin`.")
@task(aliases=["docker-new-db"])
def new_db(ctx):
"""Delete your database and create a new one with fake data"""
print("* Stopping services and deleting volumes first")
ctx.run("docker-compose down --volumes")
print("* Applying database migrations.")
migrate(ctx)
print("* Creating fake data")
manage(ctx, "load_fake_data")
l10n_block_inventory(ctx)
create_super_user(ctx)
@task(aliases=["docker-catchup", "catchup"])
def catch_up(ctx):
"""Rebuild images, install dependencies, and apply migrations"""
print("* Stopping services first")
ctx.run("docker-compose down")
print("* Rebuilding images and install dependencies")
ctx.run("docker-compose build")
print("* Install Node dependencies")
npm_install(ctx)
print("* Sync Python dependencies")
pip_sync(ctx)
print("* Applying database migrations.")
migrate(ctx)
print("* Updating block information.")
l10n_block_inventory(ctx)
print("\n* Start your dev server with:\n docker-compose up")
@task(aliases=["docker-new-env"])
def new_env(ctx):
"""Get a new dev environment and a new database with fake data"""
with ctx.cd(ROOT):
ctx.run(f"pipenv run python network-api/manage.py {command}", **PLATFORM_ARG)
print("* Setting default environment variables")
if os.path.isfile(".env"):
print(
"* Stripping quotes and making sure your DATABASE_URL and ALLOWED_HOSTS are properly setup"
)
create_env_file(".env")
else:
print("* Creating a new .env")
create_env_file("env.default")
print("* Stopping project's containers and delete volumes if necessary")
ctx.run("docker-compose down --volumes")
print("* Building Docker images")
ctx.run("docker-compose build")
print("* Install Node dependencies")
npm_install(ctx)
# Create a python virtualenv if necessary
if not os.path.isdir("dockerpythonvenv"):
print("* Creating a Python virtualenv")
ctx.run(
"docker-compose run --rm backend python -m venv dockerpythonvenv",
**PLATFORM_ARG,
)
print("Done!")
print("* Updating pip")
ctx.run(
"docker-compose run --rm backend ./dockerpythonvenv/bin/pip install -U pip==20.0.2",
**PLATFORM_ARG,
)
print("* Installing pip-tools")
ctx.run(
"docker-compose run --rm backend ./dockerpythonvenv/bin/pip install pip-tools",
**PLATFORM_ARG,
)
print("* Sync Python dependencies")
pip_sync(ctx)
print("* Applying database migrations.")
migrate(ctx)
print("* Creating fake data.")
manage(ctx, "load_fake_data")
print("* Updating block information.")
l10n_block_inventory(ctx)
create_super_user(ctx)
print("\n* Start your dev server with:\n docker-compose up")
@task
def runserver(ctx):
"""Start a web server"""
manage(ctx, "runserver 0.0.0.0:8000")
# Javascript shorthands
@task(aliases=["docker-npm"])
def npm(ctx, command):
"""Shorthand to npm. inv docker-npm \"[COMMAND] [ARG]\""""
with ctx.cd(ROOT):
ctx.run(f"docker-compose run --rm watch-static-files npm {command}")
@task
@task(aliases=["docker-npm-install"])
def npm_install(ctx):
"""Install Node dependencies"""
with ctx.cd(ROOT):
ctx.run("docker-compose run --rm watch-static-files npm install")
# Django shorthands
@task(aliases=["docker-manage"])
def manage(ctx, command):
"""Shorthand to manage.py. inv docker-manage \"[COMMAND] [ARG]\""""
with ctx.cd(ROOT):
ctx.run(
f"docker-compose run --rm backend ./dockerpythonvenv/bin/python network-api/manage.py {command}",
**PLATFORM_ARG,
)
@task(aliases=["docker-migrate"])
def migrate(ctx):
"""Updates database schema"""
manage(ctx, "migrate", flag="noinput")
manage(ctx, "migrate --no-input")
@task
@task(aliases=["docker-makemigrations"])
def makemigrations(ctx):
"""Creates new migration(s) for apps"""
manage(ctx, "makemigrations")
@task
# Tests
@task(aliases=["docker-test"])
def test(ctx):
"""Run both Node and Python tests"""
test_node(ctx)
test_python(ctx)
@task(aliases=["docker-test-python"])
def test_python(ctx):
"""Run python tests"""
print("* Running flake8")
ctx.run(
"docker-compose run --rm backend ./dockerpythonvenv/bin/python -m flake8 tasks.py network-api",
**PLATFORM_ARG,
)
print("* Running tests")
manage(ctx, "test")
@task(aliases=["docker-test-node"])
def test_node(ctx):
"""Run node tests"""
print("* Running tests")
ctx.run("docker-compose run --rm watch-static-files npm run test")
# Localisation
@task(aliases=["docker-l10n-sync"])
def l10n_sync(ctx):
"""Sync localizable fields in the database"""
manage(ctx, "sync_page_translation_fields")
@task
@task(aliases=["docker-l10n-update"])
def l10n_update(ctx):
"""Update localizable field data (copies from
original unlocalized to default localized field)"""
"""Update localizable field data (copies from original unlocalized to default localized field)"""
manage(ctx, "update_translation_fields")
@task
@task(aliases=["docker-makemessages"])
def makemessages(ctx):
"""Extract all template messages in .po files for localization"""
ctx.run("./translation-management.sh import")
@ -111,219 +247,43 @@ def makemessages(ctx):
ctx.run("./translation-management.sh export")
@task
@task(aliases=["docker-compilemessages"])
def compilemessages(ctx):
"""Compile the latest translations"""
with ctx.cd(LOCALE_DIR):
manage(ctx, "compilemessages")
@task
def test(ctx):
"""Run tests"""
print("* Running flake8")
ctx.run(f"pipenv run flake8 tasks.py network-api", **PLATFORM_ARG)
print("* Running tests")
manage(ctx, "test")
@task
def setup(ctx):
"""Prepare your dev environment after a fresh git clone"""
# Pip-tools
@task(aliases=["docker-pip-compile"])
def pip_compile(ctx, command):
"""Shorthand to pip-tools. inv pip-compile \"[COMMAND] [ARG]\""""
with ctx.cd(ROOT):
print("* Setting default environment variables.")
if os.path.isfile(".env"):
print("* Keeping your existing .env")
else:
print("* Creating a new .env")
copy("env.default", ".env")
print("* Installing npm dependencies and build.")
ctx.run("npm install && npm run build:dev")
print("* Installing Python dependencies.")
ctx.run("pipenv install --dev")
print("* Applying database migrations.")
migrate(ctx)
print("* Updating localizable fields.")
l10n_sync(ctx)
l10n_update(ctx)
print("* Creating fake data.")
manage(ctx, "load_fake_data")
print("* Updating block information.")
manage(ctx, "block_inventory")
# Windows doesn't support pty, skipping this step
if platform == 'win32':
print("\nAll done!\n"
"To create an admin user: pipenv run python network-api/manage.py createsuperuser\n"
"To start your dev server: inv runserver")
else:
print("Creating superuser.")
ctx.run("pipenv run python network-api/manage.py createsuperuser", pty=True)
print("All done! To start your dev server, run the following:\n inv runserver")
ctx.run(
f"docker-compose run --rm backend ./dockerpythonvenv/bin/pip-compile {command}",
**PLATFORM_ARG,
)
@task(aliases=["catchup"])
def catch_up(ctx):
"""Install dependencies and apply migrations"""
print("* Installing npm dependencies and build.")
ctx.run("npm install && npm run build:dev")
print("* Installing Python dependencies.")
ctx.run("pipenv install --dev")
print("* Applying database migrations.")
migrate(ctx)
print("* Updating localizable fields.")
l10n_sync(ctx)
l10n_update(ctx)
print("* Updating block information.")
manage(ctx, "block_inventory")
# Tasks with Docker
def docker_l10n_block_inventory(ctx):
print("* Updating localizable fields")
docker_l10n_sync(ctx)
docker_l10n_update(ctx)
print("* Updating block information")
docker_manage(ctx, "block_inventory")
def docker_create_super_user(ctx):
preamble = "from django.contrib.auth.models import User;"
create = "User.objects.create_superuser('admin', 'admin@example.com', 'admin')"
docker_manage(ctx, f"shell -c \"{preamble} {create}\"")
print("\nCreated superuser `admin` with password `admin`.")
@task
def docker_manage(ctx, command):
"""Shorthand to manage.py. inv docker.manage \"[COMMAND] [ARG]\""""
@task(aliases=["docker-pip-compile-lock"])
def pip_compile_lock(ctx):
"""Lock prod and dev dependencies"""
with ctx.cd(ROOT):
ctx.run(f"docker-compose run --rm backend pipenv run python network-api/manage.py {command}", **PLATFORM_ARG)
ctx.run(
"docker-compose run --rm backend ./dockerpythonvenv/bin/pip-compile",
**PLATFORM_ARG,
)
ctx.run(
"docker-compose run --rm backend ./dockerpythonvenv/bin/pip-compile dev-requirements.in",
**PLATFORM_ARG,
)
@task
def docker_pipenv(ctx, command):
"""Shorthand to pipenv. inv docker.pipenv \"[COMMAND] [ARG]\""""
@task(aliases=["docker-pip-sync"])
def pip_sync(ctx):
"""Sync your python virtualenv"""
with ctx.cd(ROOT):
ctx.run(f"docker-compose run --rm backend pipenv {command}")
@task
def docker_npm(ctx, command):
"""Shorthand to npm. inv docker.npm \"[COMMAND] [ARG]\""""
with ctx.cd(ROOT):
ctx.run(f"docker-compose run --rm watch-static-files npm {command}")
@task
def docker_migrate(ctx):
"""Updates database schema"""
docker_manage(ctx, "migrate --no-input")
@task
def docker_makemigrations(ctx):
"""Creates new migration(s) for apps"""
docker_manage(ctx, "makemigrations")
@task
def docker_l10n_sync(ctx):
"""Sync localizable fields in the database"""
docker_manage(ctx, "sync_page_translation_fields")
@task
def docker_l10n_update(ctx):
"""Update localizable field data (copies from original unlocalized to default localized field)"""
docker_manage(ctx, "update_translation_fields")
@task
def docker_makemessages(ctx):
"""Extract all template messages in .po files for localization"""
ctx.run("./translation-management.sh import")
docker_manage(ctx, locale_abstraction_instructions)
ctx.run("./translation-management.sh export")
@task
def docker_compilemessages(ctx):
"""Compile the latest translations"""
with ctx.cd(LOCALE_DIR):
docker_manage(ctx, "compilemessages")
@task
def docker_test(ctx):
docker_test_node(ctx)
docker_test_python(ctx)
@task
def docker_test_python(ctx):
"""Run python tests"""
print("* Running flake8")
ctx.run("docker-compose run --rm backend pipenv run flake8 tasks.py network-api", **PLATFORM_ARG)
print("* Running tests")
docker_manage(ctx, "test")
@task
def docker_test_node(ctx):
"""Run node tests"""
print("* Running tests")
ctx.run("docker-compose run --rm watch-static-files npm run test", **PLATFORM_ARG)
@task
def docker_new_db(ctx):
"""Delete your database and create a new one with fake data"""
print("* Stopping services and deleting volumes first")
ctx.run("docker-compose down --volumes")
print("* Applying database migrations.")
docker_migrate(ctx)
print("* Creating fake data")
docker_manage(ctx, "load_fake_data")
docker_l10n_block_inventory(ctx)
docker_create_super_user(ctx)
@task(aliases=["docker-catchup"])
def docker_catch_up(ctx):
"""Rebuild images and apply migrations"""
print("* Stopping services first")
ctx.run("docker-compose down")
print("* Rebuilding images and install dependencies")
ctx.run("docker-compose build")
print("* Applying database migrations.")
docker_migrate(ctx)
print("* Updating block information.")
docker_l10n_block_inventory(ctx)
@task
def docker_new_env(ctx):
"""Get a new dev environment and a new database with fake data"""
with ctx.cd(ROOT):
print("* Setting default environment variables")
if os.path.isfile(".env"):
print("* Stripping quotes and making sure your DATABASE_URL and ALLOWED_HOSTS are properly setup")
create_docker_env_file(".env")
else:
print("* Creating a new .env")
create_docker_env_file("env.default")
print("* Stopping project's containers and delete volumes if necessary")
ctx.run("docker-compose down --volumes")
print("* Building Docker images")
ctx.run("docker-compose build --no-cache", **PLATFORM_ARG)
print("* Applying database migrations.")
docker_migrate(ctx)
print("* Creating fake data.")
docker_manage(ctx, "load_fake_data")
print("* Updating block information.")
docker_l10n_block_inventory(ctx)
docker_create_super_user(ctx)
print("\n* Start your dev server with:\n docker-compose up")
ctx.run(
"docker-compose run --rm backend ./dockerpythonvenv/bin/pip-sync requirements.txt dev-requirements.txt",
**PLATFORM_ARG,
)