diff --git a/README.rst b/README.rst index 1857264e..c5a91e55 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ Then, in any case you need to enable the plugins:: Services will have to be re-configured and restarted, so you are probably better off just running launch again:: - tutor local launch + tutor local launch Note that this plugins is compatible with `Kubernetes integration `__. When deploying to a Kubernetes cluster, run instead:: @@ -124,19 +124,17 @@ Development When running Tutor in development mode, the ecommerce service is accessible at http://ecommerce.local.overhang.io:8130. -To mount a local ecommerce repository in the ecommerce container, add the following content to the ``$(tutor config printroot)/env/dev/docker-compose.override.yml`` file:: +To mount a local ecommerce repository in the ecommerce container, add an auto-mounted repository with:: - version: "3.7" - services: - ecommerce: - volumes: - - /absolute/path/to/ecommerce:/openedx/ecommerce + tutor mounts add /path/to/ecommerce -You will have to generate static assets in your local repository:: +Rebuild the "ecommerce" Docker image:: - tutor dev run ecommerce npm install - tutor dev run ecommerce ./node_modules/.bin/bower install --allow-root - tutor dev run ecommerce python3 manage.py update_assets --skip-collect + tutor images build ecommerce + +Lauch your platform again:: + + tutor dev launch To attach a debugger to the ecommerce service, run:: diff --git a/changelog.d/20230919_104436_regis_auto_mount.md b/changelog.d/20230919_104436_regis_auto_mount.md new file mode 100644 index 00000000..2e051b24 --- /dev/null +++ b/changelog.d/20230919_104436_regis_auto_mount.md @@ -0,0 +1 @@ +- [Feature] Improve support of auto-mounted ecommerce repository. (by @regisb) diff --git a/tutorecommerce/patches/local-docker-compose-jobs-services b/tutorecommerce/patches/local-docker-compose-jobs-services index ff630e50..75e992cb 100644 --- a/tutorecommerce/patches/local-docker-compose-jobs-services +++ b/tutorecommerce/patches/local-docker-compose-jobs-services @@ -4,4 +4,7 @@ ecommerce-job: DJANGO_SETTINGS_MODULE: ecommerce.settings.tutor.production volumes: - ../plugins/ecommerce/apps/ecommerce/settings:/openedx/ecommerce/ecommerce/settings/tutor:ro - depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }} \ No newline at end of file + {%- for mount in iter_mounts(MOUNTS, "ecommerce") %} + - {{ mount }} + {%- endfor %} + depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }} diff --git a/tutorecommerce/patches/local-docker-compose-services b/tutorecommerce/patches/local-docker-compose-services index 7612a4d9..3d0247fa 100644 --- a/tutorecommerce/patches/local-docker-compose-services +++ b/tutorecommerce/patches/local-docker-compose-services @@ -5,6 +5,9 @@ ecommerce: restart: unless-stopped volumes: - ../plugins/ecommerce/apps/ecommerce/settings:/openedx/ecommerce/ecommerce/settings/tutor:ro + {%- for mount in iter_mounts(MOUNTS, "ecommerce") %} + - {{ mount }} + {%- endfor %} depends_on: - discovery - lms diff --git a/tutorecommerce/plugin.py b/tutorecommerce/plugin.py index 6ab5be19..5c864724 100644 --- a/tutorecommerce/plugin.py +++ b/tutorecommerce/plugin.py @@ -224,9 +224,11 @@ def _mount_ecommerce_apps(mounts, path_basename): @tutor_hooks.Filters.IMAGES_BUILD_MOUNTS.add() def _mount_ecommerce_on_build(mounts: list[tuple[str, str]], host_path: str) -> list[tuple[str, str]]: path_basename = os.path.basename(host_path) - # payment MFE will be handled by the tutor-mfe plugin, but we need to fix the - # auto-mount for the ecommerce/order MFE - if path_basename == "frontend-app-ecommerce": + if path_basename == "ecommerce": + mounts.append(("ecommerce", "ecommerce-src")) + elif path_basename == "frontend-app-ecommerce": + # payment MFE will be handled by the tutor-mfe plugin, but we need to fix the + # auto-mount for the ecommerce/order MFE mounts.remove(("mfe", "ecommerce-src")) mounts.remove(("ecommerce-dev", "ecommerce-src")) mounts.append(("mfe", "orders-src")) diff --git a/tutorecommerce/templates/ecommerce/build/ecommerce/Dockerfile b/tutorecommerce/templates/ecommerce/build/ecommerce/Dockerfile index 1e1ba966..b7d25add 100644 --- a/tutorecommerce/templates/ecommerce/build/ecommerce/Dockerfile +++ b/tutorecommerce/templates/ecommerce/build/ecommerce/Dockerfile @@ -3,19 +3,48 @@ FROM docker.io/ubuntu:20.04 as minimal RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked{% endif %} \ + --mount=type=cache,target=/var/lib/apt,sharing=locked{% endif %} \ apt update && \ - apt install -y curl git-core language-pack-en libmysqlclient-dev libssl-dev python3 python3-pip python3-venv + apt install -y curl git-core language-pack-en + +###### Checkout code +FROM minimal as checkout + +ARG ECOMMERCE_REPOSITORY=https://github.com/edx/ecommerce.git +ARG ECOMMERCE_VERSION='{{ OPENEDX_COMMON_VERSION }}' +RUN mkdir -p /openedx/ecommerce && \ + git clone $ECOMMERCE_REPOSITORY --branch $ECOMMERCE_VERSION --depth 1 /openedx/ecommerce + +# Identify tutor user to cherry-pick commits +RUN git config --global user.email "tutor@overhang.io" \ + && git config --global user.name "Tutor" + +##### Empty layer with just the repo at the root. +# This is useful when overriding the build context with a host repo: +# docker build --build-context /path/to/ecommerce +FROM scratch as ecommerce-src +COPY --from=checkout /openedx/ecommerce / + +###### Install python and virtual environment +FROM minimal as python + +RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked{% endif %} \ + apt update && \ + apt install -y libmysqlclient-dev libssl-dev python3 python3-pip python3-venv ARG APP_USER_ID=1000 RUN if [ "$APP_USER_ID" = 0 ]; then echo "app user may not be root" && false; fi RUN useradd --home-dir /openedx --create-home --shell /bin/bash --uid ${APP_USER_ID} app USER ${APP_USER_ID} +# Create cache dir. Otherwise, for some reason, it becomes owned by root. +RUN mkdir /openedx/.cache + # Create python venv RUN python3 -m venv /openedx/venv/ ENV PATH "/openedx/venv/bin:$PATH" -RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared {% endif %}pip install \ +RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared,uid=${APP_USER_ID} {% endif %}pip install \ # https://pypi.org/project/setuptools/ # https://pypi.org/project/pip/ # https://pypi.org/project/wheel/ @@ -27,26 +56,19 @@ RUN pip install nodeenv==1.7.0 RUN nodeenv /openedx/nodeenv --node=16.20.0 --prebuilt ENV PATH /openedx/nodeenv/bin:${PATH} -# Install ecommerce -ARG ECOMMERCE_REPOSITORY=https://github.com/edx/ecommerce.git -ARG ECOMMERCE_VERSION='{{ OPENEDX_COMMON_VERSION }}' -RUN mkdir -p /openedx/ecommerce && \ - git clone $ECOMMERCE_REPOSITORY --branch $ECOMMERCE_VERSION --depth 1 /openedx/ecommerce +# Copy ecommerce source code +COPY --from=ecommerce-src --chown=app:app / /openedx/ecommerce WORKDIR /openedx/ecommerce -# Identify tutor user to cherry-pick commits -RUN git config --global user.email "tutor@overhang.io" \ - && git config --global user.name "Tutor" - # Install npm, bower requirements ARG NPM_REGISTRY='{{ NPM_REGISTRY }}' RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.npm/,sharing=shared,uid=${APP_USER_ID} {% endif %}npm clean-install --verbose --no-audit --registry=$NPM_REGISTRY RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/bower,sharing=shared,uid=${APP_USER_ID} {% endif %}./node_modules/.bin/bower install --allow-root # python requirements -RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared {% endif %}pip install -r requirements.txt +RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared,uid=${APP_USER_ID} {% endif %}pip install -r requirements.txt # https://pypi.org/project/uWSGI/ -RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared {% endif %}pip install uwsgi==2.0.21 +RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared,uid=${APP_USER_ID} {% endif %}pip install uwsgi==2.0.21 # Install private requirements: this is useful for installing custom payment processors. COPY --chown=app:app ./requirements/ /openedx/requirements @@ -54,7 +76,7 @@ RUN cd /openedx/requirements/ \ && touch ./private.txt \ && pip install -r ./private.txt -{% for extra_requirement in ECOMMERCE_EXTRA_PIP_REQUIREMENTS %}RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared {% endif %}pip install '{{ extra_requirement }}' +{% for extra_requirement in ECOMMERCE_EXTRA_PIP_REQUIREMENTS %}RUN {% if is_buildkit_enabled() %}--mount=type=cache,target=/openedx/.cache/pip,sharing=shared,uid=${APP_USER_ID} {% endif %}pip install '{{ extra_requirement }}' {% endfor %} # Collect static assets (aka: "make static") diff --git a/tutorecommerce/templates/ecommerce/tasks/ecommerce/init b/tutorecommerce/templates/ecommerce/tasks/ecommerce/init index 6e97a110..eb89016e 100644 --- a/tutorecommerce/templates/ecommerce/tasks/ecommerce/init +++ b/tutorecommerce/templates/ecommerce/tasks/ecommerce/init @@ -42,3 +42,12 @@ --discovery_api_url={% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ DISCOVERY_HOST }}/api/v1/ \ --enable-microfrontend-for-basket-page=true \ --payment-microfrontend-url="{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ MFE_HOST }}/{{ ECOMMERCE_PAYMENT_MFE_APP['name'] }}" + +if [ ! -e /openedx/ecommerce/node_modules ] +then + # node_modules directory does not exist, this almost certainly means that the + # ecommerce directory was bind-mounted. We need to bootstrap that directory. + npm clean-install --verbose --no-audit + ./node_modules/.bin/bower install --allow-root + ./manage.py update_assets --skip-collect +fi