diff --git a/.github/workflows/build-retail-setup-push-tag-shared.yaml.yaml b/.github/workflows/build-retail-setup-push-tag-shared.yaml.yaml new file mode 100644 index 0000000..277bd74 --- /dev/null +++ b/.github/workflows/build-retail-setup-push-tag-shared.yaml.yaml @@ -0,0 +1,137 @@ +name: Build Retail Setup in Shared (Push Tag) + +on: + push: + tags: + - '*.*.*-develop' + - '*.*.*-staging' + - '*.*.*' + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Set variables + run: | + TAG="$( echo "${GITHUB_REF}" | cut -d'/' -f3 )" + if grep -qs -e '^.*.*-develop' <<< "${TAG}" ; then + echo "Found environment: DEVELOP - ${TAG}" + echo "MANIFESTS_ENVIRONMENT=develop" | tee "${GITHUB_ENV}" + elif grep -qs -e '^.*.*-staging' <<< "${TAG}" ; then + echo "Found environment: STAGING - ${TAG}" + echo "MANIFESTS_ENVIRONMENT=staging" | tee -a "${GITHUB_ENV}" + elif grep -qs -e '^.*.*' <<< "${TAG}" ; then + echo "No environment found, assuming: PRODUCTION - ${TAG}" + echo "MANIFESTS_ENVIRONMENT=production" | tee -a "${GITHUB_ENV}" + else + echo 'Not a valid tag. Skipping...' + exit 1 + fi + echo "TAG=$TAG" | tee -a "${GITHUB_ENV}" + VERSION="${TAG}" + echo "VERSION=${VERSION}" | tee -a "${GITHUB_ENV}" + echo "COMMIT_SHA=$GITHUB_SHA" | tee -a "${GITHUB_ENV}" + echo "IMAGE_TAG=${{ secrets.ECR }}/retail:setup-${TAG}" | tee -a "${GITHUB_ENV}" + echo "IMAGE_SOURCE_URL=https://github.com/weni-ai/retail-setup" | tee -a "${GITHUB_ENV}" + echo "MANIFESTS_REPOSITORY=weni-ai/kubernetes-manifests-retail" | tee -a "${GITHUB_ENV}" + echo "MANIFESTS_APPLICATION=retail-setup" | tee -a "${GITHUB_ENV}" + echo "MANIFESTS_PATCH_TARGET=deployment.json" | tee -a "${GITHUB_ENV}" + + - name: Check out the repo + uses: actions/checkout@v3 + with: + ref: "${{env.GITHUB_SHA}}" + # On non dispatch build not need the repo + #repository: Ilhasoft/weni-engine + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to ECR + uses: docker/login-action@v2 + with: + registry: ${{ secrets.ECR }} + username: ${{ secrets.AWS_ACCESS_KEY_ID_SHARED }} # Credentials used to push image to ECR repository + password: ${{ secrets.AWS_SECRET_ACCESS_KEY_SHARED }} + + - name: Build and push - Retail Setup Image + uses: docker/build-push-action@v3 + with: + context: . + labels: | + tag=${{env.TAG}} + commit=${{env.COMMIT_SHA}} + repository=${{env.IMAGE_SOURCE_URL}} + file: docker/Dockerfile + push: true + tags: "${{env.IMAGE_TAG}}" + no-cache: true + + - name: Check out Kubernetes Manifests + # Now, checkout in kubernetes manifests to update image in deployments patches + uses: actions/checkout@master + with: + ref: main + repository: "${{ env.MANIFESTS_REPOSITORY }}" + token: "${{ secrets.DEVOPS_GITHUB_PERMANENT_TOKEN }}" + path: ./kubernetes-manifests/ + # Its uses other path to not mix with source code repository used to build + + - name: Update image on deployment + run: | + which jq > /dev/null 2>&1 || ( sudo apt update ; sudo apt install -y jq ) + # Dep: coreutils + verlte() { + [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ] + } + verlt(){ + [ "$1" = "$2" ] && return 1 || verlte $1 $2 + } + export PROJECT_DIR="${{ env.MANIFESTS_APPLICATION }}" + ENV_DIR="kubernetes-manifests/${{ env.MANIFESTS_APPLICATION }}/${MANIFESTS_ENVIRONMENT}" + for e in ${ENV_DIR}; do + echo "Update ${e}:" + if [ ! -d "${e}" ] ; then + echo "${e}: Does not exist, skipping" + elif [ ! -r "${e}/kustomization.yaml" ] ; then + echo "${e}/kustomization.yaml: Does not readable, skipping" + elif [ ! -r "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" ] ; then + echo "${e}/${{ env.MANIFESTS_PATCH_TARGET }}: Does not readable, skipping" + else + OLD_IMAGE=$( + cat "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" \ + | jq '.[] | select(.path == "/spec/template/spec/containers/0/image") | .value' + ) + echo "Old image to replace: ${OLD_IMAGE}" + OLD_VERSION=$( + echo "${OLD_IMAGE}" \ + | sed s'/^.*[v:-]\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/'g \ + | head -n1 + ) + echo "Old image version to compare: ${OLD_VERSION}<=${{env.VERSION}}" + if verlte "${OLD_VERSION}" "${VERSION}" || [[ ! "${OLD_VERSION}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]] ; then + echo 'New configurations:' + new_configuration=$( + cat "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" \ + | jq '(..|select(.path == "/spec/template/spec/containers/0/image")?) += {value: "'"${{env.IMAGE_TAG}}"'"}' + ) + echo "${new_configuration}" + echo "${new_configuration}" > "${e}/${{ env.MANIFESTS_PATCH_TARGET }}" + else + echo "Version in file is greater than build, skipping update yaml" + fi + fi + done + + - name: Commit & Push changes + # Once made a change, commit new configuration + uses: actions-js/push@master + with: + github_token: "${{ secrets.DEVOPS_GITHUB_PERMANENT_TOKEN }}" + repository: "${{ env.MANIFESTS_REPOSITORY }}" + directory: ./kubernetes-manifests/ + branch: main + message: "From Retail Setup Build (Push Tag ${{ env.MANIFESTS_ENVIRONMENT }})" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2b275af..7707671 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ coverage.xml local_settings.py db.sqlite3 db.sqlite3-journal +static/ # Flask stuff: instance/ diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..3ad5920 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,100 @@ +#syntax = docker/dockerfile:1 + +ARG PYTHON_VERSION="3.10" +ARG POETRY_VERSION="1.8.1" + +ARG BUILD_DEPS="\ + gcc bzip2 git curl libpq-dev gettext \ + libgdal-dev python3-cffi python3-gdal \ + python3-dev default-libmysqlclient-dev build-essential \ + build-essential \ + cmake \ + autoconf pkg-config autoconf libtool automake \ + libmariadb-dev" + +ARG RUNTIME_DEPS="\ + git \ + tzdata \ + postgresql-client \ + netcat-traditional \ + curl \ + gosu \ + gdal-bin" + +FROM python:${PYTHON_VERSION}-slim as base + +ARG POETRY_VERSION + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + DEBIAN_FRONTEND=noninteractive \ + PROJECT=Retail-engine \ + PROJECT_PATH=/home/app \ + APP_USER=app_user \ + APP_GROUP=app_group \ + USER_ID=1999 \ + GROUP_ID=1999 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 \ + PATH="/install/bin:${PATH}" \ + APP_PORT=${APP_PORT} \ + APPLICATION_NAME="Retail-engine" \ + RUNTIME_DEPS=${RUNTIME_DEPS} \ + BUILD_DEPS=${BUILD_DEPS} \ + PYTHONIOENCODING=UTF-8 \ + LIBRARY_PATH=/lib:/usr/lib + +ARG COMPRESS_ENABLED +ARG BRANDING_ENABLED + +RUN addgroup --gid "${GROUP_ID}" "${APP_GROUP}" \ + && useradd --system -m -d "${PROJECT_PATH}" -u "${USER_ID}" -g "${GROUP_ID}" "${APP_USER}" + +WORKDIR "${PROJECT_PATH}" + +RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache + +FROM base as build-poetry + +ARG POETRY_VERSION + +COPY pyproject.toml poetry.lock ./ + +RUN --mount=type=cache,mode=0755,target=/pip_cache,id=pip pip install --cache-dir /pip_cache -U poetry=="${POETRY_VERSION}" \ + && poetry cache clear -n --all pypi \ + && poetry export --without-hashes --output requirements.txt +# && poetry add -n --lock $(cat pip-requires.txt) \ + +FROM base as build + +ARG BUILD_DEPS + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y ${BUILD_DEPS} + +COPY --from=build-poetry "${PROJECT_PATH}/requirements.txt" /tmp/dep/ +RUN --mount=type=cache,mode=0755,target=/pip_cache,id=pip pip install --cache-dir /pip_cache --prefix=/install -r /tmp/dep/requirements.txt + +FROM base + +ARG BUILD_DEPS +ARG RUNTIME_DEPS + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && SUDO_FORCE_REMOVE=yes apt-get remove --purge -y ${BUILD_DEPS} \ + && apt-get autoremove -y \ + && apt-get install -y --no-install-recommends ${RUNTIME_DEPS} \ + && rm -rf /usr/share/man /usr/share/doc + +COPY --from=build /install /usr/local +COPY --chown=${APP_USER}:${APP_GROUP} . ${PROJECT_PATH} + +RUN ls + +USER "${APP_USER}:${APP_GROUP}" +EXPOSE 8000 +ENTRYPOINT ["bash", "./docker/entrypoint.sh"] +CMD ["start"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index fd3dc3d..fd26eab 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -17,3 +17,17 @@ services: environment: - RABBITMQ_DEFAULT_USER=guest - RABBITMQ_DEFAULT_PASS=guest + + retail-setup: + build: + context: .. + dockerfile: ./docker/Dockerfile + ports: + - "8000:8000" + environment: + - DEBUG=${DEBUG:-true} + - ALLOWED_HOSTS=${ALLOWED_HOSTS:-*} + - SECRET_KEY=${SECRET_KEY:-123} + - DATABASE_URL=${DATABASE_URL:-postgresql://retail:retail@database:5432/retail} + depends_on: + - database diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..a6911d8 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +export GUNICORN_APP=${GUNICORN_APP:-"retail.wsgi"} +export GUNICORN_CONF=${GUNICORN_CONF:-"${PROJECT_PATH}/docker/gunicorn.conf.py"} +export LOG_LEVEL=${LOG_LEVEL:-"INFO"} + +do_gosu(){ + user="$1" + shift 1 + + is_exec="false" + if [ "$1" = "exec" ]; then + is_exec="true" + shift 1 + fi + + if [ "$(id -u)" = "0" ]; then + if [ "${is_exec}" = "true" ]; then + exec gosu "${user}" "$@" + else + gosu "${user}" "$@" + return "$?" + fi + else + if [ "${is_exec}" = "true" ]; then + exec "$@" + else + eval '"$@"' + return "$?" + fi + fi +} + +if [[ "start" == "$1" ]]; then + echo "Running collectstatic" + do_gosu "${APP_USER}:${APP_GROUP}" python manage.py collectstatic --noinput + echo "Starting server" + do_gosu "${APP_USER}:${APP_GROUP}" exec gunicorn "${GUNICORN_APP}" -c "${GUNICORN_CONF}" +elif [[ "edaconsume" == "$1" ]]; then + echo "Running eda-consumer" + do_gosu "${APP_USER}:${APP_GROUP}" python manage.py edaconsume +else + exec "$@" +fi diff --git a/docker/gunicorn.conf.py b/docker/gunicorn.conf.py new file mode 100644 index 0000000..1f52d4c --- /dev/null +++ b/docker/gunicorn.conf.py @@ -0,0 +1,11 @@ +import os +import multiprocessing + +workers = os.environ.get("GUNICORN_WORKERS", multiprocessing.cpu_count() * 2 + 1) +proc_name = "retail" +default_proc_name = proc_name +accesslog = "-" +errorlog = "-" +capture_output = True +timeout = 120 +bind = "0.0.0.0" \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..68e02ae --- /dev/null +++ b/poetry.lock @@ -0,0 +1,358 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "amqp" +version = "5.2.0" +description = "Low-level AMQP client for Python (fork of amqplib)." +optional = false +python-versions = ">=3.6" +files = [ + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, +] + +[package.dependencies] +vine = ">=5.0.0,<6.0.0" + +[[package]] +name = "asgiref" +version = "3.8.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.8" +files = [ + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "black" +version = "24.4.2" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, + {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, + {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, + {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, + {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, + {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, + {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, + {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, + {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, + {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, + {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, + {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, + {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, + {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, + {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "django" +version = "5.0.7" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.10" +files = [ + {file = "Django-5.0.7-py3-none-any.whl", hash = "sha256:f216510ace3de5de01329463a315a629f33480e893a9024fc93d8c32c22913da"}, + {file = "Django-5.0.7.tar.gz", hash = "sha256:bd4505cae0b9bd642313e8fb71810893df5dc2ffcacaa67a33af2d5cd61888f2"}, +] + +[package.dependencies] +asgiref = ">=3.7.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-environ" +version = "0.11.2" +description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be"}, + {file = "django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"}, +] + +[package.extras] +develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] + +[[package]] +name = "flake8" +version = "7.1.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, + {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.12.0,<2.13.0" +pyflakes = ">=3.2.0,<3.3.0" + +[[package]] +name = "gunicorn" +version = "22.0.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gunicorn-22.0.0-py3-none-any.whl", hash = "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9"}, + {file = "gunicorn-22.0.0.tar.gz", hash = "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] +tornado = ["tornado (>=0.2)"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + +[[package]] +name = "psycopg2" +version = "2.9.9" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "psycopg2-2.9.9-cp310-cp310-win32.whl", hash = "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"}, + {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"}, + {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"}, + {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"}, + {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"}, + {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"}, + {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"}, + {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"}, + {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"}, + {file = "psycopg2-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"}, + {file = "psycopg2-2.9.9-cp39-cp39-win32.whl", hash = "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"}, + {file = "psycopg2-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"}, + {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"}, +] + +[[package]] +name = "pycodestyle" +version = "2.12.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, + {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, +] + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + +[[package]] +name = "sqlparse" +version = "0.5.1" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.8" +files = [ + {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, + {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, +] + +[package.extras] +dev = ["build", "hatch"] +doc = ["sphinx"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "vine" +version = "5.1.0" +description = "Python promises." +optional = false +python-versions = ">=3.6" +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[[package]] +name = "weni-eda" +version = "0.0.1" +description = "" +optional = false +python-versions = "<4.0,>=3.10" +files = [ + {file = "weni_eda-0.0.1-py3-none-any.whl", hash = "sha256:d269174220fbb3615eadef58d246d32b95ca4e4c55d535714752dd2cc7e3cb0d"}, + {file = "weni_eda-0.0.1.tar.gz", hash = "sha256:2f1234ae450e2d3cf26bb674599fdaf7f6dda61a926247c6a5e10042b33ec09f"}, +] + +[package.dependencies] +amqp = ">=5.2.0,<6.0.0" + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "8c3bc7280dc206e50f450b552fee4d78235d57e5d9d9583ff1df5d3142bc43ad" diff --git a/pyproject.toml b/pyproject.toml index 0f561fc..9eac40a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ django-environ = "^0.11.2" psycopg2-binary = "^2.9.9" psycopg2 = "^2.9.9" weni-eda = "^0.0.1" +gunicorn = "^22.0.0" [tool.poetry.group.dev.dependencies] diff --git a/retail/settings.py b/retail/settings.py index ffe03ed..ba5b4f3 100644 --- a/retail/settings.py +++ b/retail/settings.py @@ -127,6 +127,7 @@ # https://docs.djangoproject.com/en/5.0/howto/static-files/ STATIC_URL = "static/" +STATIC_ROOT = "static" # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field