diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..70b20e021b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,41 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + + - package-ecosystem: docker + directory: build/bench + schedule: + interval: daily + + - package-ecosystem: docker + directory: build/erpnext-nginx + schedule: + interval: daily + + - package-ecosystem: docker + directory: build/erpnext-worker + schedule: + interval: daily + + - package-ecosystem: docker + directory: build/frappe-nginx + schedule: + interval: daily + + - package-ecosystem: docker + directory: build/frappe-socketio + schedule: + interval: daily + + - package-ecosystem: docker + directory: build/frappe-worker + schedule: + interval: daily + + - package-ecosystem: npm + directory: build/frappe-socketio + schedule: + interval: daily diff --git a/.github/scripts/get-latest-tags.sh b/.github/scripts/get-latest-tags.sh new file mode 100755 index 0000000000..cfcf85e999 --- /dev/null +++ b/.github/scripts/get-latest-tags.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e +set -x + +get_tag() { + tags=$(git ls-remote --refs --tags --sort='v:refname' "https://github.com/$1" "v$2.*") + tag=$(echo "$tags" | tail -n1 | sed 's/.*\///') + echo "$tag" +} + +FRAPPE_VERSION=$(get_tag frappe/frappe "$VERSION") +ERPNEXT_VERSION=$(get_tag frappe/erpnext "$VERSION") + +cat <>"$GITHUB_ENV" +FRAPPE_VERSION=$FRAPPE_VERSION +ERPNEXT_VERSION=$ERPNEXT_VERSION +GIT_BRANCH=version-$VERSION +VERSION=$VERSION +EOL diff --git a/.github/workflows/build_develop.yml b/.github/workflows/build_develop.yml new file mode 100644 index 0000000000..90f9876cc0 --- /dev/null +++ b/.github/workflows/build_develop.yml @@ -0,0 +1,127 @@ +name: Build Develop + +on: + pull_request: + branches: + - main + paths: + - .github/** + - build/** + - installation/** + - tests/** + - .dockerignore + - docker-bake.hcl + - docker-compose.yml + - env* + + schedule: + # Every day at 12:00 pm + - cron: 0 0 * * * + + workflow_dispatch: + +env: + IS_AUTHORIZED_RUN: ${{ github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' }} + +jobs: + build_bench: + name: Bench + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login + uses: docker/login-action@v1 + if: env.IS_AUTHORIZED_RUN == 'true' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and test + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: bench-test + + - name: Push + uses: docker/bake-action@v1.6.0 + if: env.IS_AUTHORIZED_RUN == 'true' + with: + files: docker-bake.hcl + targets: bench-build + push: true + + build_frappe: + name: Frappe + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login + uses: docker/login-action@v1 + if: env.IS_AUTHORIZED_RUN == 'true' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: frappe-develop-test + load: true + + - name: Test + run: ./tests/test-frappe.sh + + - name: Push + if: env.IS_AUTHORIZED_RUN == 'true' + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: frappe-develop + push: true + + build_erpnext: + name: ERPNext + runs-on: ubuntu-latest + needs: build_frappe + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login + uses: docker/login-action@v1 + if: env.IS_AUTHORIZED_RUN == 'true' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: erpnext-develop-test + load: true + + - name: Test + run: FRAPPE_VERSION=develop ./tests/test-erpnext.sh + + - name: Push + if: env.IS_AUTHORIZED_RUN == 'true' + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: erpnext-develop + push: true diff --git a/.github/workflows/build_stable.yml b/.github/workflows/build_stable.yml new file mode 100644 index 0000000000..f46ef5960d --- /dev/null +++ b/.github/workflows/build_stable.yml @@ -0,0 +1,146 @@ +name: Build Stable + +on: + pull_request: + branches: + - main + paths: + - .github/** + - build/** + - installation/** + - tests/** + - .dockerignore + - docker-bake.hcl + - docker-compose.yml + - env* + push: + branches: + - main + paths: + - .github/** + - build/** + - installation/** + - tests/** + - .dockerignore + - docker-bake.hcl + - docker-compose.yml + - env* + + # Triggered from frappe/frappe and frappe/erpnext on releases + repository_dispatch: + + workflow_dispatch: + +env: + IS_AUTHORIZED_RUN: ${{ github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' }} + +jobs: + build_frappe: + name: Frappe + runs-on: ubuntu-latest + strategy: + matrix: + version: [12, 13] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login + uses: docker/login-action@v1 + if: env.IS_AUTHORIZED_RUN == 'true' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get latest versions + run: ./.github/scripts/get-latest-tags.sh + env: + VERSION: ${{ matrix.version }} + + - name: Build + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: frappe-stable-test + load: true + + - name: Push + if: env.IS_AUTHORIZED_RUN == 'true' + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: frappe-stable + push: true + env: + GIT_TAG: ${{ env.FRAPPE_VERSION }} + + build_erpnext: + name: ERPNext + runs-on: ubuntu-latest + needs: build_frappe + strategy: + matrix: + version: [12, 13] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login + uses: docker/login-action@v1 + if: env.IS_AUTHORIZED_RUN == 'true' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get latest versions + run: ./.github/scripts/get-latest-tags.sh + env: + VERSION: ${{ matrix.version }} + + - name: Build + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: erpnext-stable-test + load: true + + - name: Push + if: env.IS_AUTHORIZED_RUN == 'true' + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: erpnext-stable + push: true + env: + GIT_TAG: ${{ env.ERPNEXT_VERSION }} + + release_helm: + name: Release Helm + runs-on: ubuntu-latest + if: github.repository == 'frappe/frappe_docker' && github.event_name != 'pull_request' + needs: [build_frappe, build_erpnext] + + steps: + - name: Setup deploy key + uses: webfactory/ssh-agent@v0.5.3 + with: + ssh-private-key: ${{ secrets.HELM_DEPLOY_KEY }} + + - name: Setup Git Credentials + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Release + run: | + git clone git@github.com:frappe/helm.git && cd helm + pip install -r release_wizard/requirements.txt + ./release_wizard/wizard 13 patch --remote origin --ci diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..82362f01e8 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,18 @@ +name: Lint + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: ludeeus/action-shellcheck@1.1.0 + env: + SHELLCHECK_OPTS: -x diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c1841de17c..14d7593a73 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,18 +2,17 @@ name: Mark stale issues and pull requests on: schedule: - - cron: "0 0 * * *" + # Every day at 12:00 pm + - cron: 0 0 * * * jobs: stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue has been automatically marked as stale. You have a week to explain why you believe this is an error.' - stale-pr-message: 'This PR has been automatically marked as stale. You have a week to explain why you believe this is an error.' - stale-issue-label: 'no-issue-activity' - stale-pr-label: 'no-pr-activity' \ No newline at end of file + - uses: actions/stale@v4 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: This issue has been automatically marked as stale. You have a week to explain why you believe this is an error. + stale-pr-message: This PR has been automatically marked as stale. You have a week to explain why you believe this is an error. + stale-issue-label: no-issue-activity + stale-pr-label: no-pr-activity diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..376c9bdaf2 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,62 @@ +name: Integration Test + +on: + push: + branches: + - main + paths: + - .github/** + - build/** + - installation/** + - tests/** + - .dockerignore + - docker-bake.hcl + - docker-compose.yml + - env* + + pull_request: + branches: + - main + paths: + - .github/** + - build/** + - installation/** + - tests/** + - .dockerignore + - docker-bake.hcl + - docker-compose.yml + - env* + + workflow_dispatch: + + schedule: + # Every day at 01:00 am + # Develop images are built at 12:00 pm, we want to use them + # Also, we don't build new images on this event + - cron: 0 1 * * * + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Get latest versions + if: github.event_name != 'schedule' + run: ./.github/scripts/get-latest-tags.sh + env: + VERSION: 13 + + - name: Build + if: github.event_name != 'schedule' + uses: docker/bake-action@v1.6.0 + with: + files: docker-bake.hcl + targets: frappe-develop,frappe-stable + load: true + env: + GIT_TAG: ${{ env.FRAPPE_VERSION }} + + - name: Test + run: ./tests/integration-test.sh diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6d6f8fcb2e..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,187 +0,0 @@ -sudo: required - -dist: bionic - -language: python - -python: - - '3.6' - -services: - - docker - -before_install: - - if [[ "$BUILD" != "development" ]]; then - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; - sudo apt-get update && sudo apt-get -y install git; - fi - - if [[ $BUILD == "development" ]];then - sudo apt-get update && sudo apt-get -y install docker-compose; - fi - - chmod u+x ./travis.py - -after_success: - - docker --version - -jobs: - include: - - stage: "Build Frappe bench development environment (latest)" - if: branch = develop AND type != pull_request - script: - - docker build -t frappe/bench:latest -f build/bench/Dockerfile . - - docker push frappe/bench:latest - - stage: "Frappe (edge)" - if: branch = develop AND type != pull_request - script: - - ./travis.py frappe --worker --tag latest - - ./travis.py frappe --worker --tag edge --tag-only - - ./travis.py frappe --worker --tag develop --tag-only - - stage: "Frappe (edge)" - if: branch = develop AND type != pull_request - script: - - ./travis.py frappe --nginx --tag latest - - ./travis.py frappe --nginx --tag edge --tag-only - - ./travis.py frappe --nginx --tag develop --tag-only - - stage: "Frappe (edge)" - if: branch = develop AND type != pull_request - script: - - ./travis.py frappe --socketio --tag latest - - ./travis.py frappe --socketio --tag edge --tag-only - - ./travis.py frappe --socketio --tag develop --tag-only - - stage: "ERPNext (edge)" - if: branch = develop AND type != pull_request - script: - - ./travis.py erpnext --worker --tag latest - - ./travis.py erpnext --worker --tag edge --tag-only - - ./travis.py erpnext --worker --tag develop --tag-only - - stage: "ERPNext (edge)" - if: branch = develop AND type != pull_request - script: - - ./travis.py erpnext --nginx --tag latest - - ./travis.py erpnext --nginx --tag edge --tag-only - - ./travis.py erpnext --nginx --tag develop --tag-only - - stage: "Frappe (v13)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --worker --git-version 13 - - ./travis.py frappe --worker --tag v13 --tag-only - - ./travis.py frappe --worker --tag version-13 --tag-only - - stage: "Frappe (v13)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --nginx --git-version 13 - - ./travis.py frappe --nginx --tag v13 --tag-only - - ./travis.py frappe --nginx --tag version-13 --tag-only - - stage: "Frappe (v13)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --socketio --git-version 13 - - ./travis.py frappe --socketio --tag v13 --tag-only - - ./travis.py frappe --socketio --tag version-13 --tag-only - - stage: "ERPNext (v13)" - if: branch = master AND type != pull_request - script: - - ./travis.py erpnext --worker --git-version 13 - - ./travis.py erpnext --worker --tag v13 --tag-only - - ./travis.py erpnext --worker --tag version-13 --tag-only - - stage: "ERPNext (v13)" - if: branch = master AND type != pull_request - script: - - ./travis.py erpnext --nginx --git-version 13 - - ./travis.py erpnext --nginx --tag v13 --tag-only - - ./travis.py erpnext --nginx --tag version-13 --tag-only - - stage: "Frappe (v12)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --worker --git-version 12 - - ./travis.py frappe --worker --tag v12 --tag-only - - ./travis.py frappe --worker --tag version-12 --tag-only - - stage: "Frappe (v12)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --nginx --git-version 12 - - ./travis.py frappe --nginx --tag v12 --tag-only - - ./travis.py frappe --nginx --tag version-12 --tag-only - - stage: "Frappe (v12)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --socketio --git-version 12 - - ./travis.py frappe --socketio --tag v12 --tag-only - - ./travis.py frappe --socketio --tag version-12 --tag-only - - stage: "ERPNext (v12)" - if: branch = master AND type != pull_request - script: - - ./travis.py erpnext --worker --git-version 12 - - ./travis.py erpnext --worker --tag v12 --tag-only - - ./travis.py erpnext --worker --tag version-12 --tag-only - - stage: "ERPNext (v12)" - if: branch = master AND type != pull_request - script: - - ./travis.py erpnext --nginx --git-version 12 - - ./travis.py erpnext --nginx --tag v12 --tag-only - - ./travis.py erpnext --nginx --tag version-12 --tag-only - - stage: "Frappe (v11)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --worker --git-version 11 - - ./travis.py frappe --worker --tag v11 --tag-only - - ./travis.py frappe --worker --tag version-11 --tag-only - - stage: "Frappe (v11)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --nginx --git-version 11 - - ./travis.py frappe --nginx --tag v11 --tag-only - - ./travis.py frappe --nginx --tag version-11 --tag-only - - stage: "Frappe (v11)" - if: branch = master AND type != pull_request - script: - - ./travis.py frappe --socketio --git-version 11 - - ./travis.py frappe --socketio --tag v11 --tag-only - - ./travis.py frappe --socketio --tag version-11 --tag-only - - stage: "ERPNext (v11)" - if: branch = master AND type != pull_request - script: - - ./travis.py erpnext --worker --git-version 11 - - ./travis.py erpnext --worker --tag v11 --tag-only - - ./travis.py erpnext --worker --tag version-11 --tag-only - - stage: "ERPNext (v11)" - if: branch = master AND type != pull_request - script: - - ./travis.py erpnext --nginx --git-version 11 - - ./travis.py erpnext --nginx --tag v11 --tag-only - - ./travis.py erpnext --nginx --tag version-11 --tag-only - - stage: "Build and test edge images" - if: type = pull_request - before_install: - - sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - - sudo chmod +x /usr/local/bin/docker-compose - - sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose - - sudo apt-get update && sudo apt-get -y install w3m shellcheck - script: - - ./tests/check-format.sh - - docker build -t frappe/frappe-socketio:edge -f build/frappe-socketio/Dockerfile . - - docker build -t frappe/frappe-worker:develop -f build/frappe-worker/Dockerfile . - - docker build -t frappe/erpnext-worker:edge -f build/erpnext-worker/Dockerfile . - - docker build -t frappe/frappe-nginx:develop -f build/frappe-nginx/Dockerfile . - - docker build -t frappe/erpnext-nginx:edge -f build/erpnext-nginx/Dockerfile . - - ./tests/docker-test.sh - - stage: "Pull and test edge images" - if: branch = develop AND type != pull_request - before_install: - - sudo apt-get update && sudo apt-get -y install docker-compose w3m - script: - - ./tests/docker-test.sh - - stage: "Helm Chart Release" - if: branch = master AND type != pull_request - env: - - GIT_SSH_COMMAND="ssh -i ${TRAVIS_BUILD_DIR}/deploy_key" - before_install: - - openssl aes-256-cbc -K $encrypted_189e52c2c347_key -iv $encrypted_189e52c2c347_iv -in deploy_key.enc -out deploy_key -d; - chmod 400 deploy_key; - - ssh-keyscan github.com >> $HOME/.ssh/known_hosts 2>/dev/null; - install: - - pip install --upgrade pip - script: - - git clone git@github.com:frappe/helm.git && cd helm - - pip install -r release_wizard/requirements.txt - - ./release_wizard/wizard 13 patch --remote origin --ci diff --git a/README.md b/README.md index f66784feb3..a346ca6ab1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ -| Develop | [![Build Status](https://travis-ci.com/frappe/frappe_docker.svg?branch=develop)](https://travis-ci.com/frappe/frappe_docker) | -|---------|-----------------------------------------------------------------------------------------------------------------------------| -| Master | [![Build Status](https://travis-ci.com/frappe/frappe_docker.svg?branch=master)](https://travis-ci.com/frappe/frappe_docker) | +[![Build Stable](https://github.com/frappe/frappe_docker/actions/workflows/build_stable.yml/badge.svg)](https://github.com/frappe/frappe_docker/actions/workflows/build_stable.yml) +[![Build Develop](https://github.com/frappe/frappe_docker/actions/workflows/build_develop.yml/badge.svg)](https://github.com/frappe/frappe_docker/actions/workflows/build_develop.yml) ## Getting Started diff --git a/build/bench/Dockerfile b/build/bench/Dockerfile index d4c9d6d016..f7cdaeb824 100644 --- a/build/bench/Dockerfile +++ b/build/bench/Dockerfile @@ -1,14 +1,20 @@ -# Frappe Bench Dockerfile -FROM debian:buster-slim +FROM python:3.9-slim-bullseye as build + +LABEL author=frappé ARG GIT_REPO=https://github.com/frappe/bench.git ARG GIT_BRANCH=develop -LABEL author=frappé +ENV NODE_VERSION=14.18.1 +ENV NODE_VERSION_FRAPPEV11=10.24.1 +ENV NVM_DIR /home/frappe/.nvm +ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH} +ENV WKHTMLTOPDF_VERSION 0.12.6-1 -RUN apt-get update -y && apt-get install \ +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ + # For frappe framework git \ - wkhtmltopdf \ mariadb-client \ postgresql-client \ gettext-base \ @@ -29,6 +35,7 @@ RUN apt-get update -y && apt-get install \ watch \ tree \ nano \ + less \ software-properties-common \ bash-completion \ # For psycopg2 @@ -37,7 +44,7 @@ RUN apt-get update -y && apt-get install \ libffi-dev \ liblcms2-dev \ libldap2-dev \ - libmariadbclient-dev \ + libmariadb-dev \ libsasl2-dev \ libtiff5-dev \ libwebp-dev \ @@ -47,68 +54,53 @@ RUN apt-get update -y && apt-get install \ ssh-client \ # VSCode container requirements net-tools \ - # PYTHON - python3-dev \ - python3-pip \ - python3-setuptools \ - python3-tk \ - python-virtualenv \ - less -y && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \ - && dpkg-reconfigure --frontend=noninteractive locales + && dpkg-reconfigure --frontend=noninteractive locales -# Detect arch, download and install wkhtmltox -RUN if [ `uname -m` = 'aarch64' ]; then export ARCH=arm64; fi \ - && if [ `uname -m` = 'x86_64' ]; then export ARCH=amd64; fi \ - && wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_${ARCH}.deb \ - && dpkg -i wkhtmltox_0.12.6-1.buster_${ARCH}.deb && rm wkhtmltox_0.12.6-1.buster_${ARCH}.deb +# Detect arch, download and install wkhtmltopdf +RUN if [ "$(uname -m)" = "aarch64" ]; then export ARCH=arm64; fi \ + && if [ "$(uname -m)" = "x86_64" ]; then export ARCH=amd64; fi \ + && downloaded_file=wkhtmltox_$WKHTMLTOPDF_VERSION.buster_${ARCH}.deb \ + && wget -q https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \ + && dpkg -i $downloaded_file \ + && rm $downloaded_file # Create new user with home directory, improve docker compatibility with UID/GID 1000, add user to sudo group, allow passwordless sudo, switch to that user and change directory to user home directory -RUN groupadd -g 1000 frappe -RUN useradd --no-log-init -r -m -u 1000 -g 1000 -G sudo frappe -RUN echo "frappe ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +RUN groupadd -g 1000 frappe \ + && useradd --no-log-init -r -m -u 1000 -g 1000 -G sudo frappe \ + && echo "frappe ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + USER frappe WORKDIR /home/frappe # Clone and install bench in the local user home directory # For development, bench source is located in ~/.bench RUN git clone ${GIT_REPO} --depth 1 -b ${GIT_BRANCH} .bench \ - && pip3 install --user -e .bench + && pip install --user -e .bench # Export python executables for Dockerfile -ENV PATH=/home/frappe/.local/bin:$PATH +ENV PATH /home/frappe/.local/bin:$PATH # Export python executables for interactive shell RUN echo "export PATH=/home/frappe/.local/bin:\$PATH" >> /home/frappe/.bashrc -# Print version and verify bashrc is properly sourced so that everything works in the Dockerfile -RUN bench --version -# Print version and verify bashrc is properly sourced so that everything works in the interactive shell -RUN bash -c "bench --version" - -# !!! UPDATE NODEJS PERIODICALLY WITH LATEST VERSIONS !!! -# https://nodejs.org/en/about/releases/ -# https://nodejs.org/download/release/latest-v10.x/ -# https://nodejs.org/download/release/latest-v14.x/ -ENV NODE_VERSION=14.17.0 -ENV NODE_VERSION_FRAPPEV11=10.24.1 - # Install nvm with node -RUN wget https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh -RUN chmod +x install.sh -RUN ./install.sh -ENV NVM_DIR=/home/frappe/.nvm +RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \ + && . ${NVM_DIR}/nvm.sh \ + # Install node for Frappe V11, install yarn + && nvm install ${NODE_VERSION_FRAPPEV11} \ + && nvm use v${NODE_VERSION_FRAPPEV11} \ + && npm install -g yarn \ + && nvm install ${NODE_VERSION} \ + && nvm use v${NODE_VERSION} \ + && npm install -g yarn \ + && nvm alias default v${NODE_VERSION} \ + && rm -rf ${NVM_DIR}/.cache -# Install node for Frappe V11, install yarn -RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION_FRAPPEV11} -RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION_FRAPPEV11} && npm install -g yarn -# Install node for latest frappe, set as default, install node -RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION} -RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION} && npm install -g yarn -RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION} -ENV PATH="/home/frappe/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}" +EXPOSE 8000-8005 9000-9005 6787 + +FROM build as test # Print version and verify bashrc is properly sourced so that everything works in the Dockerfile RUN node --version \ @@ -119,4 +111,5 @@ RUN bash -c "node --version" \ && bash -c "npm --version" \ && bash -c "yarn --version" -EXPOSE 8000-8005 9000-9005 6787 +RUN bench --help +RUN bash -c "bench --help" \ No newline at end of file diff --git a/build/common/commands/background.py b/build/common/commands/background.py deleted file mode 100644 index a26b79342b..0000000000 --- a/build/common/commands/background.py +++ /dev/null @@ -1,11 +0,0 @@ -from frappe.utils.scheduler import start_scheduler - - -def main(): - print("Starting background scheduler . . .") - start_scheduler() - exit(0) - - -if __name__ == "__main__": - main() diff --git a/build/common/commands/console.py b/build/common/commands/console.py deleted file mode 100644 index b5c06b5ecf..0000000000 --- a/build/common/commands/console.py +++ /dev/null @@ -1,32 +0,0 @@ -import sys -import frappe -import IPython - -from frappe.utils import get_sites - - -def console(site): - "Start ipython console for a site" - if site not in get_sites(): - print("Site {0} does not exist on the current bench".format(site)) - return - - frappe.init(site=site) - frappe.connect() - frappe.local.lang = frappe.db.get_default("lang") - all_apps = frappe.get_installed_apps() - for app in all_apps: - locals()[app] = __import__(app) - print("Apps in this namespace:\n{}".format(", ".join(all_apps))) - IPython.embed(display_banner="", header="") - - -def main(): - site = sys.argv[-1] - console(site) - if frappe.redis_server: - frappe.redis_server.connection_pool.disconnect() - - -if __name__ == "__main__": - main() diff --git a/build/common/commands/drop.py b/build/common/commands/drop.py deleted file mode 100644 index da7595244f..0000000000 --- a/build/common/commands/drop.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import frappe - -from frappe.commands.site import _drop_site -from constants import ARCHIVE_SITES_PATH -from utils import get_password - - -def main(): - site_name = os.environ.get("SITE_NAME", 'site1.localhost') - db_root_username = os.environ.get("DB_ROOT_USER", 'root') - mariadb_root_password = get_password("MYSQL_ROOT_PASSWORD", 'admin') - postgres_root_password = get_password("POSTGRES_PASSWORD") - db_root_password = mariadb_root_password - - if postgres_root_password: - db_root_password = postgres_root_password - - force = True if os.environ.get("FORCE", None) else False - no_backup = True if os.environ.get("NO_BACKUP", None) else False - frappe.init(site_name, new_site=True) - - _drop_site( - site=site_name, - root_login=db_root_username, - root_password=db_root_password, - archived_sites_path=ARCHIVE_SITES_PATH, - force=force, - no_backup=no_backup - ) - - if frappe.redis_server: - frappe.redis_server.connection_pool.disconnect() - - exit(0) - - -if __name__ == "__main__": - main() diff --git a/build/common/commands/worker.py b/build/common/commands/worker.py deleted file mode 100644 index ba10722044..0000000000 --- a/build/common/commands/worker.py +++ /dev/null @@ -1,12 +0,0 @@ -import os -from frappe.utils.background_jobs import start_worker - - -def main(): - queue = os.environ.get("WORKER_TYPE", "default") - start_worker(queue, False) - exit(0) - - -if __name__ == "__main__": - main() diff --git a/build/common/worker/docker-entrypoint.sh b/build/common/worker/docker-entrypoint.sh deleted file mode 100755 index 56ec3a9e1b..0000000000 --- a/build/common/worker/docker-entrypoint.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash - -function configureEnv() { - if [[ ! -f /home/frappe/frappe-bench/sites/common_site_config.json ]]; then - - if [[ -z "${MARIADB_HOST}" && -z "${POSTGRES_HOST}" ]]; then - echo "MARIADB_HOST or POSTGRES_HOST is not set" >&2 - exit 1 - fi - - if [[ -z "${REDIS_CACHE}" ]]; then - echo "REDIS_CACHE is not set" >&2 - exit 1 - fi - - if [[ -z "${REDIS_QUEUE}" ]]; then - echo "REDIS_QUEUE is not set" >&2 - exit 1 - fi - - if [[ -z "${REDIS_SOCKETIO}" ]]; then - echo "REDIS_SOCKETIO is not set" >&2 - exit 1 - fi - - if [[ -z "${SOCKETIO_PORT}" ]]; then - echo "SOCKETIO_PORT is not set" >&2 - exit 1 - fi - - if [[ -z "${DB_PORT}" ]]; then - export DB_PORT=3306 - fi - - export DB_HOST="${MARIADB_HOST:-$POSTGRES_HOST}" - - envsubst '${DB_HOST} - ${DB_PORT} - ${REDIS_CACHE} - ${REDIS_QUEUE} - ${REDIS_SOCKETIO} - ${SOCKETIO_PORT}' /home/frappe/frappe-bench/sites/common_site_config.json - fi -} - -function checkConnection() { - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/check_connection.py -} - -function checkConfigExists() { - COUNTER=0 - while [[ ! -e /home/frappe/frappe-bench/sites/common_site_config.json && ${COUNTER} -le 30 ]]; do - sleep 1 - ((COUNTER = COUNTER + 1)) - echo "config file not created, retry ${COUNTER}" >&2 - done - - if [[ ! -e /home/frappe/frappe-bench/sites/common_site_config.json ]]; then - echo "timeout: config file not created" >&2 - exit 1 - fi -} - -if [[ ! -e /home/frappe/frappe-bench/sites/apps.txt ]]; then - find /home/frappe/frappe-bench/apps -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | - sort -r >/home/frappe/frappe-bench/sites/apps.txt -fi - -# symlink node_modules -ln -sfn /home/frappe/frappe-bench/sites/assets/frappe/node_modules \ - /home/frappe/frappe-bench/apps/frappe/node_modules - -case "$1" in - - start) - configureEnv - checkConnection - - [[ -z "${WORKERS}" ]] && WORKERS='2' - - [[ -z "${FRAPPE_PORT}" ]] && FRAPPE_PORT='8000' - - [[ -z "${WORKER_CLASS}" ]] && WORKER_CLASS='gthread' - - LOAD_CONFIG_FILE="" - [[ "${WORKER_CLASS}" == "gevent" ]] && - LOAD_CONFIG_FILE="-c /home/frappe/frappe-bench/commands/gevent_patch.py" - - if [[ -n "${AUTO_MIGRATE}" ]]; then - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/auto_migrate.py - fi - - /home/frappe/frappe-bench/env/bin/gunicorn ${LOAD_CONFIG_FILE} -b 0.0.0.0:${FRAPPE_PORT} \ - --worker-tmp-dir /dev/shm \ - --threads=4 \ - --workers ${WORKERS} \ - --worker-class=${WORKER_CLASS} \ - --log-file=- \ - -t 120 frappe.app:application --preload - ;; - - worker) - checkConfigExists - checkConnection - # default WORKER_TYPE=default - - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/worker.py - ;; - - schedule) - checkConfigExists - checkConnection - - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/background.py - - ;; - - new) - checkConfigExists - checkConnection - - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/new.py - exit - ;; - - drop) - checkConfigExists - checkConnection - - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/drop.py - exit - ;; - - migrate) - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/migrate.py - exit - ;; - - doctor) - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/doctor.py "${@:2}" - exit - ;; - - backup) - - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/backup.py - exit - ;; - - console) - if [[ -z "$2" ]]; then - echo "Need to specify a sitename with the command:" >&2 - echo "console " >&2 - exit 1 - fi - - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/console.py "$2" - exit - ;; - - push-backup) - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/push_backup.py - exit - ;; - - restore-backup) - /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/restore_backup.py - exit - ;; - *) - exec "$@" - ;; -esac diff --git a/build/erpnext-nginx/Dockerfile b/build/erpnext-nginx/Dockerfile index 31abf79519..69e2614f7e 100644 --- a/build/erpnext-nginx/Dockerfile +++ b/build/erpnext-nginx/Dockerfile @@ -1,26 +1,32 @@ -ARG NODE_IMAGE_TAG=14-buster-slim +ARG NODE_IMAGE_TAG=14-bullseye-slim ARG DOCKER_REGISTRY_PREFIX=frappe ARG IMAGE_TAG=develop -FROM node:${NODE_IMAGE_TAG} +FROM node:${NODE_IMAGE_TAG} as builder ARG GIT_REPO=https://github.com/frappe/erpnext ARG GIT_BRANCH=develop + ARG FRAPPE_BRANCH=${GIT_BRANCH} +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + python2 \ + git \ + build-essential \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + COPY build/erpnext-nginx/install_app.sh /install_app -RUN chmod +x /install_app && \ - apt-get update -y && \ - apt-get install build-essential git python2 -y && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +RUN chmod +x /install_app \ + && /install_app erpnext ${GIT_REPO} ${GIT_BRANCH} ${FRAPPE_BRANCH} -RUN /install_app erpnext ${GIT_REPO} ${GIT_BRANCH} ${FRAPPE_BRANCH} FROM ${DOCKER_REGISTRY_PREFIX}/frappe-nginx:${IMAGE_TAG} -COPY --from=0 /home/frappe/frappe-bench/sites/ /var/www/html/ -COPY --from=0 /rsync /rsync +COPY --from=builder --chown=1000:1000 /home/frappe/frappe-bench/sites/ /var/www/html/ +COPY --from=builder /rsync /rsync + RUN echo "erpnext" >> /var/www/html/apps.txt VOLUME [ "/assets" ] diff --git a/build/erpnext-nginx/install_app.sh b/build/erpnext-nginx/install_app.sh index d3e307690d..085dbaeb20 100755 --- a/build/erpnext-nginx/install_app.sh +++ b/build/erpnext-nginx/install_app.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + APP_NAME=${1} APP_REPO=${2} APP_BRANCH=${3} @@ -7,37 +9,32 @@ FRAPPE_BRANCH=${4} [ "${APP_BRANCH}" ] && BRANCH="-b ${APP_BRANCH}" -mkdir -p /home/frappe/frappe-bench/sites/assets +mkdir -p /home/frappe/frappe-bench cd /home/frappe/frappe-bench -echo -ne "frappe\n${APP_NAME}" >/home/frappe/frappe-bench/sites/apps.txt +mkdir -p apps "sites/assets/${APP_NAME}" +echo -ne "frappe\n${APP_NAME}" >sites/apps.txt -mkdir -p apps -cd apps -git clone --depth 1 https://github.com/frappe/frappe -b ${FRAPPE_BRANCH} -git clone --depth 1 ${APP_REPO} ${BRANCH} ${APP_NAME} +git clone --depth 1 -b "${FRAPPE_BRANCH}" https://github.com/frappe/frappe apps/frappe +# shellcheck disable=SC2086 +git clone --depth 1 ${BRANCH} ${APP_REPO} apps/${APP_NAME} echo "Install frappe NodeJS dependencies . . ." -cd /home/frappe/frappe-bench/apps/frappe -yarn +cd apps/frappe +yarn --pure-lockfile + echo "Install ${APP_NAME} NodeJS dependencies . . ." -cd /home/frappe/frappe-bench/apps/${APP_NAME} -yarn -echo "Build browser assets . . ." -cd /home/frappe/frappe-bench/apps/frappe -yarn production --app ${APP_NAME} -echo "Install frappe NodeJS production dependencies . . ." -cd /home/frappe/frappe-bench/apps/frappe -yarn install --production=true -echo "Install ${APP_NAME} NodeJS production dependencies . . ." -cd /home/frappe/frappe-bench/apps/${APP_NAME} -yarn install --production=true - -mkdir -p /home/frappe/frappe-bench/sites/assets/${APP_NAME} -cp -R /home/frappe/frappe-bench/apps/${APP_NAME}/${APP_NAME}/public/* /home/frappe/frappe-bench/sites/assets/${APP_NAME} +yarn --pure-lockfile --cwd "../${APP_NAME}" + +echo "Build ${APP_NAME} assets . . ." +yarn production --app "${APP_NAME}" + +cd /home/frappe/frappe-bench +# shellcheck disable=SC2086 +cp -R apps/${APP_NAME}/${APP_NAME}/public/* sites/assets/${APP_NAME} # Add frappe and all the apps available under in frappe-bench here echo "rsync -a --delete /var/www/html/assets/frappe /assets" >/rsync echo "rsync -a --delete /var/www/html/assets/${APP_NAME} /assets" >>/rsync chmod +x /rsync -rm /home/frappe/frappe-bench/sites/apps.txt +rm sites/apps.txt diff --git a/build/erpnext-worker/Dockerfile b/build/erpnext-worker/Dockerfile index 8b1e16f0ff..a26b4f9e01 100644 --- a/build/erpnext-worker/Dockerfile +++ b/build/erpnext-worker/Dockerfile @@ -5,4 +5,11 @@ FROM ${DOCKER_REGISTRY_PREFIX}/frappe-worker:${IMAGE_TAG} ARG GIT_REPO=https://github.com/frappe/erpnext ARG GIT_BRANCH=develop +USER root +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + gcc \ + && rm -rf /var/lib/apt/lists/* + +USER frappe RUN install_app erpnext ${GIT_REPO} ${GIT_BRANCH} diff --git a/build/frappe-nginx/Dockerfile b/build/frappe-nginx/Dockerfile index 26fda3a1f0..a1fca6d61f 100644 --- a/build/frappe-nginx/Dockerfile +++ b/build/frappe-nginx/Dockerfile @@ -2,61 +2,77 @@ # This is done to ensures that node-sass binary remains common. # node-sass is required to enable website theme feature used # by Website Manager role in Frappe Framework -FROM python:3.7-slim-buster +ARG PYTHON_VERSION=3.9 +FROM python:${PYTHON_VERSION}-slim-bullseye as builder -ARG GIT_REPO=https://github.com/leam-tech/frappe +ARG GIT_REPO=github.com/leam-tech/frappe ARG GIT_BRANCH=version-13-fixes +# GITHUB TOKEN SETUP +ARG GH_ACCESS_TOKEN + +ENV NODE_VERSION=14.18.1 ENV NVM_DIR=/root/.nvm -ENV NODE_VERSION=14.17.0 -ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}" -RUN apt-get update -y \ - && apt-get install wget python2 git build-essential -y \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* \ - && wget https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh \ - && chmod +x install.sh \ - && ./install.sh \ - && . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION} \ - && nvm use v${NODE_VERSION} && npm install -g yarn +ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH} + +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + git \ + build-essential \ + wget \ + # python2 for version-12 builds + python2 \ + && rm -rf /var/lib/apt/lists/* + +# Install nvm with node and yarn +RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \ + && . ${NVM_DIR}/nvm.sh \ + && nvm install ${NODE_VERSION} \ + && npm install -g yarn \ + && rm -rf ${NVM_DIR}/.cache WORKDIR /home/frappe/frappe-bench -RUN mkdir -p /home/frappe/frappe-bench/sites \ - && echo "frappe" > /home/frappe/frappe-bench/sites/apps.txt -RUN mkdir -p apps sites/assets/css \ - && cd apps \ - && git clone --depth 1 ${GIT_REPO} --branch $GIT_BRANCH +RUN mkdir -p apps sites/assets/css sites/assets/frappe /var/www/error_pages +RUN echo "frappe" > sites/apps.txt -RUN cd /home/frappe/frappe-bench/apps/frappe \ +RUN --mount=type=secret,id=GH_ACCESS_TOKEN git clone --depth 1 -b ${GIT_BRANCH} https://${GH_ACCESS_TOKEN}@${GIT_REPO} apps/frappe +RUN cd apps/frappe \ && yarn \ && yarn run production \ && yarn install --production=true -RUN node --version \ - && npm --version \ - && yarn --version - RUN git clone --depth 1 https://github.com/frappe/bench /tmp/bench \ - && mkdir -p /var/www/error_pages \ && cp -r /tmp/bench/bench/config/templates /var/www/error_pages -RUN mkdir -p /home/frappe/frappe-bench/sites/assets/frappe/ \ - && cp -R /home/frappe/frappe-bench/apps/frappe/frappe/public/* /home/frappe/frappe-bench/sites/assets/frappe \ - && cp -R /home/frappe/frappe-bench/apps/frappe/node_modules /home/frappe/frappe-bench/sites/assets/frappe/ +RUN cp -R apps/frappe/frappe/public/* sites/assets/frappe \ + && cp -R apps/frappe/node_modules sites/assets/frappe/ + +FROM nginxinc/nginx-unprivileged:latest -FROM nginx:latest -COPY --from=0 /home/frappe/frappe-bench/sites /var/www/html/ -COPY --from=0 /var/www/error_pages /var/www/ -COPY build/common/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template +USER root + +RUN usermod -u 1000 nginx && groupmod -g 1000 nginx + +COPY --from=builder --chown=1000:1000 /home/frappe/frappe-bench/sites /var/www/html/ +COPY --from=builder --chown=1000:1000 /var/www/error_pages /var/www/ +COPY build/frappe-nginx/nginx-default.conf.template /etc/nginx/conf.d/default.conf.template COPY build/frappe-nginx/docker-entrypoint.sh / -RUN apt-get update && apt-get install -y rsync && apt-get clean \ - && rm -rf /var/lib/apt/lists/* \ - && echo "#!/bin/bash" > /rsync \ +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + rsync \ + && rm -rf /var/lib/apt/lists/* + +RUN echo "#!/bin/bash" > /rsync \ && chmod +x /rsync +RUN mkdir /assets VOLUME [ "/assets" ] +RUN chown -R nginx:nginx /assets /etc/nginx/conf.d/ /var/www/html/ + +USER nginx + ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"] diff --git a/build/frappe-nginx/docker-entrypoint.sh b/build/frappe-nginx/docker-entrypoint.sh index e1a2927760..976c470408 100755 --- a/build/frappe-nginx/docker-entrypoint.sh +++ b/build/frappe-nginx/docker-entrypoint.sh @@ -8,6 +8,7 @@ rsync -a --delete /var/www/html/assets/* /assets /rsync +# shellcheck disable=SC2012 touch /var/www/html/sites/.build -r "$(ls -td /assets/* | head -n 1)" [[ -z "${FRAPPE_PY}" ]] && FRAPPE_PY='0.0.0.0' @@ -30,12 +31,15 @@ touch /var/www/html/sites/.build -r "$(ls -td /assets/* | head -n 1)" [[ -z "${HTTP_HOST}" ]] && HTTP_HOST="\$http_host" +[[ -z "${WEB_PORT}" ]] && WEB_PORT="8080" + [[ -z "${SKIP_NGINX_TEMPLATE_GENERATION}" ]] && SKIP_NGINX_TEMPLATE_GENERATION='0' if [[ ${SKIP_NGINX_TEMPLATE_GENERATION} == 1 ]]; then echo "Skipping default NGINX template generation. Please mount your own NGINX config file inside /etc/nginx/conf.d" else echo "Generating default template" + # shellcheck disable=SC2016 envsubst '${FRAPPE_PY} ${FRAPPE_PY_PORT} ${FRAPPE_SOCKETIO} @@ -45,14 +49,17 @@ else ${UPSTREAM_REAL_IP_RECURSIVE} ${FRAPPE_SITE_NAME_HEADER} ${HTTP_HOST} - ${UPSTREAM_REAL_IP_HEADER}' \ + ${UPSTREAM_REAL_IP_HEADER} + ${WEB_PORT}' \ /etc/nginx/conf.d/default.conf fi echo "Waiting for frappe-python to be available on ${FRAPPE_PY} port ${FRAPPE_PY_PORT}" +# shellcheck disable=SC2016 timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' ${FRAPPE_PY} ${FRAPPE_PY_PORT} echo "Frappe-python available on ${FRAPPE_PY} port ${FRAPPE_PY_PORT}" echo "Waiting for frappe-socketio to be available on ${FRAPPE_SOCKETIO} port ${SOCKETIO_PORT}" +# shellcheck disable=SC2016 timeout 10 bash -c 'until printf "" 2>>/dev/null >>/dev/tcp/$0/$1; do sleep 1; done' ${FRAPPE_SOCKETIO} ${SOCKETIO_PORT} echo "Frappe-socketio available on ${FRAPPE_SOCKETIO} port ${SOCKETIO_PORT}" diff --git a/build/common/nginx-default.conf.template b/build/frappe-nginx/nginx-default.conf.template similarity index 99% rename from build/common/nginx-default.conf.template rename to build/frappe-nginx/nginx-default.conf.template index c3d90614d1..c3ce9b9f77 100644 --- a/build/common/nginx-default.conf.template +++ b/build/frappe-nginx/nginx-default.conf.template @@ -13,7 +13,7 @@ map $http_x_forwarded_proto $proxy_x_forwarded_proto { } server { - listen 80; + listen ${WEB_PORT}; server_name $http_host; root /var/www/html; diff --git a/build/frappe-socketio/Dockerfile b/build/frappe-socketio/Dockerfile index e7b72e096b..3294bb4f6f 100644 --- a/build/frappe-socketio/Dockerfile +++ b/build/frappe-socketio/Dockerfile @@ -1,35 +1,34 @@ -FROM alpine/git +FROM alpine/git as builder ARG GIT_REPO=https://github.com/frappe/frappe.git ARG GIT_BRANCH=develop -RUN git clone ${GIT_REPO} /opt/frappe -b ${GIT_BRANCH} --depth 1 +RUN git clone --depth 1 -b ${GIT_BRANCH} ${GIT_REPO} /opt/frappe -FROM node:buster-slim +FROM node:bullseye-slim # Add frappe user RUN useradd -ms /bin/bash frappe +WORKDIR /home/frappe/frappe-bench # Create bench directories and set ownership -RUN mkdir -p /home/frappe/frappe-bench/sites /home/frappe/frappe-bench/apps/frappe \ +RUN mkdir -p sites apps/frappe \ && chown -R frappe:frappe /home/frappe -# Download socketio and purge curl package -COPY build/frappe-socketio/package.json /home/frappe/frappe-bench/apps/frappe -COPY --from=0 /opt/frappe/socketio.js /home/frappe/frappe-bench/apps/frappe/socketio.js -COPY --from=0 /opt/frappe/node_utils.js /home/frappe/frappe-bench/apps/frappe/node_utils.js +# Download socketio +COPY build/frappe-socketio/package.json apps/frappe +COPY --from=builder /opt/frappe/socketio.js apps/frappe/socketio.js +COPY --from=builder /opt/frappe/node_utils.js apps/frappe/node_utils.js -RUN cd /home/frappe/frappe-bench/apps/frappe \ - && npm install --only=production \ - && node --version \ - && npm --version +RUN cd apps/frappe \ + && npm install --only=prod # Setup docker-entrypoint COPY build/frappe-socketio/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh -RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat +# backwards compat +RUN ln -s /usr/local/bin/docker-entrypoint.sh / USER frappe - WORKDIR /home/frappe/frappe-bench/sites ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/build/frappe-socketio/docker-entrypoint.sh b/build/frappe-socketio/docker-entrypoint.sh index a7ac66b2d9..ec3478131b 100755 --- a/build/frappe-socketio/docker-entrypoint.sh +++ b/build/frappe-socketio/docker-entrypoint.sh @@ -1,15 +1,17 @@ -#!/bin/bash -e +#!/bin/bash + +set -e function checkConfigExists() { COUNTER=0 while [[ ! -e /home/frappe/frappe-bench/sites/common_site_config.json && ${COUNTER} -le 30 ]]; do - ((COUNTER = COUNTER + 1)) - echo "config file not created, retry ${COUNTER}" sleep 1 + ((COUNTER = COUNTER + 1)) + echo "config file not created, retry ${COUNTER}" >&2 done if [[ ! -e /home/frappe/frappe-bench/sites/common_site_config.json ]]; then - echo "timeout: config file not created" + echo "timeout: config file not created" >&2 exit 1 fi } @@ -17,11 +19,6 @@ function checkConfigExists() { if [[ "$1" == 'start' ]]; then checkConfigExists node /home/frappe/frappe-bench/apps/frappe/socketio.js - -elif [[ "$1" == 'doctor' ]]; then - node /home/frappe/frappe-bench/apps/frappe/health.js - else exec -c "$@" - fi diff --git a/build/frappe-worker/Dockerfile b/build/frappe-worker/Dockerfile index 9f477dec00..65c5689523 100644 --- a/build/frappe-worker/Dockerfile +++ b/build/frappe-worker/Dockerfile @@ -1,27 +1,35 @@ -FROM python:3.7-slim-buster +ARG PYTHON_VERSION=3.9 +FROM python:${PYTHON_VERSION}-slim-bullseye # Add non root user without password RUN useradd -ms /bin/bash frappe -ARG GIT_REPO=https://github.com/leam-tech/frappe +ARG GIT_REPO=github.com/leam-tech/frappe ARG GIT_BRANCH=version-13-fixes + ARG ARCH=amd64 + +# GITHUB TOKEN SETUP +ARG GH_ACCESS_TOKEN + ENV PYTHONUNBUFFERED 1 -ENV NVM_DIR=/home/frappe/.nvm -ENV NODE_VERSION=14.17.0 -ENV PATH="/home/frappe/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}" -# Install dependencies -WORKDIR /home/frappe/frappe-bench -RUN apt-get update -y && apt-get install \ - # for frappe framework +ENV NODE_VERSION=14.18.1 +ENV NVM_DIR /home/frappe/.nvm +ENV PATH ${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/:${PATH} +ENV WKHTMLTOPDF_VERSION 0.12.6-1 + +# Install apt dependencies +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + # For frappe framework git \ mariadb-client \ postgresql-client \ gettext-base \ wget \ wait-for-it \ - # for PDF + # For PDF libjpeg62-turbo \ libx11-6 \ libxcb1 \ @@ -38,47 +46,62 @@ RUN apt-get update -y && apt-get install \ # For psycopg2 libpq-dev \ # For arm64 python wheel builds + && if [ "$(uname -m)" = "aarch64" ]; then \ + apt-get install --no-install-recommends -y \ gcc \ - g++ -y \ - # Detect arch, download and install wkhtmltox - && if [ `uname -m` = 'aarch64' ]; then export ARCH=arm64; fi \ - && if [ `uname -m` = 'x86_64' ]; then export ARCH=amd64; fi \ - && wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_${ARCH}.deb \ - && dpkg -i wkhtmltox_0.12.6-1.buster_${ARCH}.deb && rm wkhtmltox_0.12.6-1.buster_${ARCH}.deb \ - && wget https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh \ - && chown -R frappe:frappe /home/frappe \ + g++; \ + fi \ + # Install additional requirements for develop branch + && if [ "${GIT_BRANCH}" = 'develop' ]; then \ + apt-get install --no-install-recommends -y \ + libcairo2 \ + python3-cffi \ + python3-brotli \ + libpango-1.0-0 \ + libpangoft2-1.0-0 \ + libpangocairo-1.0-0; \ + fi \ && rm -rf /var/lib/apt/lists/* +# Detect arch, download and install wkhtmltopdf +RUN if [ "$(uname -m)" = "aarch64" ]; then export ARCH=arm64; fi \ + && if [ "$(uname -m)" = "x86_64" ]; then export ARCH=amd64; fi \ + && downloaded_file=wkhtmltox_$WKHTMLTOPDF_VERSION.buster_${ARCH}.deb \ + && wget -q https://github.com/wkhtmltopdf/packaging/releases/download/$WKHTMLTOPDF_VERSION/$downloaded_file \ + && dpkg -i $downloaded_file \ + && rm $downloaded_file + # Setup docker-entrypoint -COPY build/common/worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +COPY build/frappe-worker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat +WORKDIR /home/frappe/frappe-bench +RUN chown -R frappe:frappe /home/frappe USER frappe -# Install nvm with node -RUN bash install.sh \ - && . "$NVM_DIR/nvm.sh" \ - && nvm install ${NODE_VERSION} \ - && nvm use v${NODE_VERSION} \ - && nvm alias default v${NODE_VERSION} # Create frappe-bench directories RUN mkdir -p apps logs commands sites /home/frappe/backups # Setup python environment -RUN python -m venv env \ - && . env/bin/activate \ - && pip3 install --upgrade pip \ - && pip3 install gevent \ - && cd apps \ - && git clone --depth 1 -o upstream ${GIT_REPO} --branch ${GIT_BRANCH} \ - && pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/frappe +RUN python -m venv env +RUN env/bin/pip install --no-cache-dir wheel gevent + +# Install nvm with node +RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \ + && . ${NVM_DIR}/nvm.sh \ + && nvm install ${NODE_VERSION} \ + && rm -rf ${NVM_DIR}/.cache + +# Install Frappe +RUN --mount=type=secret,id=GH_ACCESS_TOKEN git clone --depth 1 -o upstream -b ${GIT_BRANCH} https://${GH_ACCESS_TOKEN}@${GIT_REPO} apps/frappe \ + && env/bin/pip install --no-cache-dir -e apps/frappe # Copy scripts and templates -COPY build/common/commands/* /home/frappe/frappe-bench/commands/ -COPY build/common/common_site_config.json.template /opt/frappe/common_site_config.json.template -COPY build/common/worker/install_app.sh /usr/local/bin/install_app -COPY build/common/worker/bench /usr/local/bin/bench -COPY build/common/worker/healthcheck.sh /usr/local/bin/healthcheck.sh +COPY build/frappe-worker/commands/* /home/frappe/frappe-bench/commands/ +COPY build/frappe-worker/common_site_config.json.template /opt/frappe/common_site_config.json.template +COPY build/frappe-worker/install_app.sh /usr/local/bin/install_app +COPY build/frappe-worker/bench /usr/local/bin/bench +COPY build/frappe-worker/healthcheck.sh /usr/local/bin/healthcheck.sh # Use sites volume as working directory WORKDIR /home/frappe/frappe-bench/sites diff --git a/build/common/worker/bench b/build/frappe-worker/bench similarity index 100% rename from build/common/worker/bench rename to build/frappe-worker/bench diff --git a/build/common/commands/auto_migrate.py b/build/frappe-worker/commands/auto_migrate.py similarity index 100% rename from build/common/commands/auto_migrate.py rename to build/frappe-worker/commands/auto_migrate.py diff --git a/build/common/commands/backup.py b/build/frappe-worker/commands/backup.py similarity index 98% rename from build/common/commands/backup.py rename to build/frappe-worker/commands/backup.py index 10ed6a923e..b6aa60a2e7 100644 --- a/build/common/commands/backup.py +++ b/build/frappe-worker/commands/backup.py @@ -36,4 +36,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/build/common/commands/check_connection.py b/build/frappe-worker/commands/check_connection.py similarity index 100% rename from build/common/commands/check_connection.py rename to build/frappe-worker/commands/check_connection.py diff --git a/build/common/commands/constants.py b/build/frappe-worker/commands/constants.py similarity index 100% rename from build/common/commands/constants.py rename to build/frappe-worker/commands/constants.py diff --git a/build/common/commands/doctor.py b/build/frappe-worker/commands/doctor.py similarity index 100% rename from build/common/commands/doctor.py rename to build/frappe-worker/commands/doctor.py diff --git a/build/common/commands/gevent_patch.py b/build/frappe-worker/commands/gevent_patch.py similarity index 100% rename from build/common/commands/gevent_patch.py rename to build/frappe-worker/commands/gevent_patch.py diff --git a/build/common/commands/migrate.py b/build/frappe-worker/commands/migrate.py similarity index 100% rename from build/common/commands/migrate.py rename to build/frappe-worker/commands/migrate.py diff --git a/build/common/commands/new.py b/build/frappe-worker/commands/new.py similarity index 100% rename from build/common/commands/new.py rename to build/frappe-worker/commands/new.py diff --git a/build/common/commands/push_backup.py b/build/frappe-worker/commands/push_backup.py similarity index 100% rename from build/common/commands/push_backup.py rename to build/frappe-worker/commands/push_backup.py diff --git a/build/common/commands/restore_backup.py b/build/frappe-worker/commands/restore_backup.py similarity index 100% rename from build/common/commands/restore_backup.py rename to build/frappe-worker/commands/restore_backup.py diff --git a/build/common/commands/utils.py b/build/frappe-worker/commands/utils.py similarity index 100% rename from build/common/commands/utils.py rename to build/frappe-worker/commands/utils.py diff --git a/build/common/common_site_config.json.template b/build/frappe-worker/common_site_config.json.template similarity index 100% rename from build/common/common_site_config.json.template rename to build/frappe-worker/common_site_config.json.template diff --git a/build/frappe-worker/docker-entrypoint.sh b/build/frappe-worker/docker-entrypoint.sh new file mode 100755 index 0000000000..74247208cc --- /dev/null +++ b/build/frappe-worker/docker-entrypoint.sh @@ -0,0 +1,191 @@ +#!/bin/bash + +function configureEnv() { + if [[ ! -f /home/frappe/frappe-bench/sites/common_site_config.json ]]; then + + if [[ -z "${MARIADB_HOST}" && -z "${POSTGRES_HOST}" ]]; then + echo "MARIADB_HOST or POSTGRES_HOST is not set" >&2 + exit 1 + fi + + if [[ -z "${REDIS_CACHE}" ]]; then + echo "REDIS_CACHE is not set" >&2 + exit 1 + fi + + if [[ -z "${REDIS_QUEUE}" ]]; then + echo "REDIS_QUEUE is not set" >&2 + exit 1 + fi + + if [[ -z "${REDIS_SOCKETIO}" ]]; then + echo "REDIS_SOCKETIO is not set" >&2 + exit 1 + fi + + if [[ -z "${SOCKETIO_PORT}" ]]; then + echo "SOCKETIO_PORT is not set" >&2 + exit 1 + fi + + if [[ -z "${DB_PORT}" ]]; then + export DB_PORT=3306 + fi + + export DB_HOST="${MARIADB_HOST:-$POSTGRES_HOST}" + + # shellcheck disable=SC2016 + envsubst '${DB_HOST} + ${DB_PORT} + ${REDIS_CACHE} + ${REDIS_QUEUE} + ${REDIS_SOCKETIO} + ${SOCKETIO_PORT}' /home/frappe/frappe-bench/sites/common_site_config.json + fi +} + +function checkConnection() { + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/check_connection.py +} + +function checkConfigExists() { + COUNTER=0 + while [[ ! -e /home/frappe/frappe-bench/sites/common_site_config.json && ${COUNTER} -le 30 ]]; do + sleep 1 + ((COUNTER = COUNTER + 1)) + echo "config file not created, retry ${COUNTER}" >&2 + done + + if [[ ! -e /home/frappe/frappe-bench/sites/common_site_config.json ]]; then + echo "timeout: config file not created" >&2 + exit 1 + fi +} + +if [[ ! -e /home/frappe/frappe-bench/sites/apps.txt ]]; then + find /home/frappe/frappe-bench/apps -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | + sort -r >/home/frappe/frappe-bench/sites/apps.txt +fi + +# symlink node_modules +ln -sfn /home/frappe/frappe-bench/sites/assets/frappe/node_modules \ + /home/frappe/frappe-bench/apps/frappe/node_modules + +case "$1" in + +start) + configureEnv + checkConnection + + [[ -z "${WORKERS}" ]] && WORKERS='2' + + [[ -z "${FRAPPE_PORT}" ]] && FRAPPE_PORT='8000' + + [[ -z "${WORKER_CLASS}" ]] && WORKER_CLASS='gthread' + + LOAD_CONFIG_FILE="" + [[ "${WORKER_CLASS}" == "gevent" ]] && + LOAD_CONFIG_FILE="-c /home/frappe/frappe-bench/commands/gevent_patch.py" + + if [[ -n "${AUTO_MIGRATE}" ]]; then + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/auto_migrate.py + fi + + # shellcheck disable=SC2086 + /home/frappe/frappe-bench/env/bin/gunicorn ${LOAD_CONFIG_FILE} -b 0.0.0.0:${FRAPPE_PORT} \ + --worker-tmp-dir /dev/shm \ + --threads=4 \ + --workers ${WORKERS} \ + --worker-class=${WORKER_CLASS} \ + --log-file=- \ + -t 120 frappe.app:application --preload + ;; + +worker) + checkConfigExists + checkConnection + + : "${WORKER_TYPE:=default}" + bench worker --queue $WORKER_TYPE + ;; + +schedule) + checkConfigExists + checkConnection + + bench schedule + ;; + +new) + checkConfigExists + checkConnection + + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/new.py + exit + ;; + +drop) + checkConfigExists + checkConnection + + : "${SITE_NAME:=site1.localhost}" + : "${DB_ROOT_USER:=root}" + : "${DB_ROOT_PASSWORD:=$POSTGRES_PASSWORD}" + : "${DB_ROOT_PASSWORD:=$MYSQL_ROOT_PASSWORD}" + : "${DB_ROOT_PASSWORD:=admin}" + + FLAGS= + if [[ ${NO_BACKUP} == 1 ]]; then + FLAGS="${FLAGS} --no-backup" + fi + if [[ ${FORCE} == 1 ]]; then + FLAGS="${FLAGS} --force" + fi + + # shellcheck disable=SC2086 + bench drop-site \ + ${SITE_NAME} \ + --root-login ${DB_ROOT_USER} \ + --root-password ${DB_ROOT_PASSWORD} \ + --archived-sites-path /home/frappe/frappe-bench/sites/archive_sites \ + ${FLAGS} + ;; + +migrate) + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/migrate.py + exit + ;; + +doctor) + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/doctor.py "${@:2}" + exit + ;; + +backup) + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/backup.py + exit + ;; + +console) + if [[ -z "$2" ]]; then + echo "Need to specify a sitename with the command:" >&2 + echo "console " >&2 + exit 1 + fi + + bench --site "$2" console + ;; + +push-backup) + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/push_backup.py + exit + ;; + +restore-backup) + /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/commands/restore_backup.py + exit + ;; +*) + exec "$@" + ;; +esac diff --git a/build/common/worker/healthcheck.sh b/build/frappe-worker/healthcheck.sh similarity index 87% rename from build/common/worker/healthcheck.sh rename to build/frappe-worker/healthcheck.sh index 6d378deda3..3c4266ee26 100755 --- a/build/common/worker/healthcheck.sh +++ b/build/frappe-worker/healthcheck.sh @@ -17,17 +17,17 @@ fi # Set REDIS host:port REDIS_CACHE=$(getUrl "${COMMON_SITE_CONFIG_JSON}" "redis_cache" | sed 's|redis://||g') if [[ "${REDIS_CACHE}" == *"/"* ]]; then - REDIS_CACHE=$(echo ${REDIS_CACHE} | cut -f1 -d"/") + REDIS_CACHE=$(echo "${REDIS_CACHE}" | cut -f1 -d"/") fi REDIS_QUEUE=$(getUrl "${COMMON_SITE_CONFIG_JSON}" "redis_queue" | sed 's|redis://||g') if [[ "${REDIS_QUEUE}" == *"/"* ]]; then - REDIS_QUEUE=$(echo ${REDIS_QUEUE} | cut -f1 -d"/") + REDIS_QUEUE=$(echo "${REDIS_QUEUE}" | cut -f1 -d"/") fi REDIS_SOCKETIO=$(getUrl "${COMMON_SITE_CONFIG_JSON}" "redis_socketio" | sed 's|redis://||g') if [[ "${REDIS_SOCKETIO}" == *"/"* ]]; then - REDIS_SOCKETIO=$(echo ${REDIS_SOCKETIO} | cut -f1 -d"/") + REDIS_SOCKETIO=$(echo "${REDIS_SOCKETIO}" | cut -f1 -d"/") fi echo "Check ${DB_HOST}:${DB_PORT}" diff --git a/build/common/worker/install_app.sh b/build/frappe-worker/install_app.sh similarity index 50% rename from build/common/worker/install_app.sh rename to build/frappe-worker/install_app.sh index d7de0842b7..6e55ec7422 100755 --- a/build/common/worker/install_app.sh +++ b/build/frappe-worker/install_app.sh @@ -6,5 +6,6 @@ APP_BRANCH=${3} [[ -n "${APP_BRANCH}" ]] && BRANCH="-b ${APP_BRANCH}" -git clone --depth 1 -o upstream ${APP_REPO} ${BRANCH} /home/frappe/frappe-bench/apps/${APP_NAME} -/home/frappe/frappe-bench/env/bin/pip3 install --no-cache-dir -e /home/frappe/frappe-bench/apps/${APP_NAME} +# shellcheck disable=SC2086 +git clone --depth 1 -o upstream "${APP_REPO}" ${BRANCH} "/home/frappe/frappe-bench/apps/${APP_NAME}" +/home/frappe/frappe-bench/env/bin/pip3 install --no-cache-dir -e "/home/frappe/frappe-bench/apps/${APP_NAME}" diff --git a/deploy_key.enc b/deploy_key.enc deleted file mode 100644 index 01360cdfc7..0000000000 Binary files a/deploy_key.enc and /dev/null differ diff --git a/devcontainer-example/docker-compose.yml b/devcontainer-example/docker-compose.yml index c46f21ca63..63f3f387f4 100644 --- a/devcontainer-example/docker-compose.yml +++ b/devcontainer-example/docker-compose.yml @@ -30,6 +30,8 @@ services: frappe: image: frappe/bench:latest command: sleep infinity + environment: + - SHELL=/bin/bash volumes: - ..:/workspace:cached working_dir: /workspace/development diff --git a/development/README.md b/development/README.md index 257f2f1abe..c73d73f07f 100644 --- a/development/README.md +++ b/development/README.md @@ -58,7 +58,7 @@ Notes: Run the following commands in the terminal inside the container. You might need to create a new terminal in VSCode. ```shell -bench init --skip-redis-config-generation --frappe-branch version-12 frappe-bench +bench init --skip-redis-config-generation --frappe-branch version-13 frappe-bench cd frappe-bench ``` diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000000..43a9a46048 --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,210 @@ +# Images + +target "bench-build" { + tags = ["frappe/bench:latest"] + dockerfile = "build/bench/Dockerfile" + target = "build" +} + +target "bench-test" { + inherits = ["bench-build"] + target = "test" +} + +target "frappe-nginx" { + dockerfile = "build/frappe-nginx/Dockerfile" +} + +target "frappe-worker" { + dockerfile = "build/frappe-worker/Dockerfile" +} + +target "frappe-socketio" { + dockerfile = "build/frappe-socketio/Dockerfile" +} + +target "erpnext-nginx" { + dockerfile = "build/erpnext-nginx/Dockerfile" +} + +target "erpnext-worker" { + dockerfile = "build/erpnext-worker/Dockerfile" +} + + +# Helpers + +target "develop-args" { + args = { + GIT_BRANCH = "develop" + IMAGE_TAG = "develop" + } +} + +variable "GIT_TAG" {} +variable "GIT_BRANCH" {} +variable "VERSION" {} + +target "stable-args" { + args = { + GIT_BRANCH = "${GIT_BRANCH}" + IMAGE_TAG = "${GIT_BRANCH}" + PYTHON_VERSION = "${VERSION}" == "12" ? "3.7" : "3.9" + } +} + +function "set_develop_tags" { + params = [repo] + result = ["${repo}:latest", "${repo}:edge", "${repo}:develop"] +} + +function "set_stable_tags" { + params = [repo] + result = ["${repo}:${GIT_TAG}", "${repo}:v${VERSION}", "${repo}:${GIT_BRANCH}"] +} + +function "set_test_tags" { + params = [repo] + result = ["${repo}:test"] +} + + +# Develop + +target "frappe-nginx-develop" { + inherits = ["frappe-nginx", "develop-args"] + tags = set_develop_tags("frappe/frappe-nginx") +} + +target "frappe-worker-develop" { + inherits = ["frappe-worker", "develop-args"] + tags = set_develop_tags("frappe/frappe-worker") +} + +target "frappe-socketio-develop" { + inherits = ["frappe-socketio", "develop-args"] + tags = set_develop_tags("frappe/frappe-socketio") +} + +target "erpnext-nginx-develop" { + inherits = ["erpnext-nginx", "develop-args"] + tags = set_develop_tags("frappe/erpnext-nginx") +} + +target "erpnext-worker-develop" { + inherits = ["erpnext-worker", "develop-args"] + tags = set_develop_tags("frappe/erpnext-worker") +} + +group "frappe-develop" { + targets = ["frappe-nginx-develop", "frappe-worker-develop", "frappe-socketio-develop"] +} + +group "erpnext-develop" { + targets = ["erpnext-nginx-develop", "erpnext-worker-develop"] +} + +# Develop test + +target "frappe-nginx-develop-test" { + inherits = ["frappe-nginx-develop"] + tags = set_test_tags("frappe/frappe-nginx") +} + +target "frappe-worker-develop-test" { + inherits = ["frappe-worker-develop"] + tags = set_test_tags("frappe/frappe-worker") +} + +target "frappe-socketio-develop-test" { + inherits = ["frappe-socketio-develop"] + tags = set_test_tags("frappe/frappe-socketio") +} + +target "erpnext-nginx-develop-test" { + inherits = ["erpnext-nginx-develop"] + tags = set_test_tags("frappe/erpnext-nginx") +} + +target "erpnext-worker-develop-test" { + inherits = ["erpnext-worker-develop"] + tags = set_test_tags("frappe/erpnext-worker") +} + +group "frappe-develop-test" { + targets = ["frappe-nginx-develop-test", "frappe-worker-develop-test", "frappe-socketio-develop-test"] +} + +group "erpnext-develop-test" { + targets = ["erpnext-nginx-develop-test", "erpnext-worker-develop-test"] +} + + +# Stable + +target "frappe-nginx-stable" { + inherits = ["frappe-nginx", "stable-args"] + tags = set_stable_tags("frappe/frappe-nginx") +} + +target "frappe-worker-stable" { + inherits = ["frappe-worker", "stable-args"] + tags = set_stable_tags("frappe/frappe-worker") +} + +target "frappe-socketio-stable" { + inherits = ["frappe-socketio", "stable-args"] + tags = set_stable_tags("frappe/frappe-socketio") +} + +target "erpnext-nginx-stable" { + inherits = ["erpnext-nginx", "stable-args"] + tags = set_stable_tags("frappe/erpnext-nginx") +} + +target "erpnext-worker-stable" { + inherits = ["erpnext-worker", "stable-args"] + tags = set_stable_tags("frappe/erpnext-worker") +} + +group "frappe-stable" { + targets = ["frappe-nginx-stable", "frappe-worker-stable", "frappe-socketio-stable"] +} + +group "erpnext-stable" { + targets = ["erpnext-nginx-stable", "erpnext-worker-stable"] +} + +# Stable test +target "frappe-nginx-stable-test" { + inherits = ["frappe-nginx-stable"] + tags = set_test_tags("frappe/frappe-nginx") +} + +target "frappe-worker-stable-test" { + inherits = ["frappe-worker-stable"] + tags = set_test_tags("frappe/frappe-worker") +} + +target "frappe-socketio-stable-test" { + inherits = ["frappe-socketio-stable"] + tags = set_test_tags("frappe/frappe-socketio") +} + +target "erpnext-nginx-stable-test" { + inherits = ["erpnext-nginx-stable"] + tags = set_test_tags("frappe/erpnext-nginx") +} + +target "erpnext-worker-stable-test" { + inherits = ["erpnext-worker-stable"] + tags = set_test_tags("frappe/erpnext-worker") +} + +group "frappe-stable-test" { + targets = ["frappe-nginx-stable-test", "frappe-worker-stable-test", "frappe-socketio-stable-test"] +} + +group "erpnext-stable-test" { + targets = ["erpnext-nginx-stable-test", "erpnext-worker-stable-test"] +} diff --git a/docker-compose.yml b/docker-compose.yml index 5ca8569b95..398c709309 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,7 +44,7 @@ services: - "traefik.http.routers.erpnext-nginx.rule=Host(${SITES})" - "${ENTRYPOINT_LABEL}" - "${CERT_RESOLVER_LABEL}" - - "traefik.http.services.erpnext-nginx.loadbalancer.server.port=80" + - "traefik.http.services.erpnext-nginx.loadbalancer.server.port=8080" volumes: - sites-vol:/var/www/html/sites:rw - assets-vol:/assets:rw diff --git a/docs/docker-swarm.md b/docs/docker-swarm.md index f415e9ee2d..692d511855 100644 --- a/docs/docker-swarm.md +++ b/docs/docker-swarm.md @@ -167,7 +167,7 @@ services: - "traefik.http.routers.erpnext-nginx-https.entrypoints=https" - "traefik.http.routers.erpnext-nginx-https.tls=true" - "traefik.http.routers.erpnext-nginx-https.tls.certresolver=le" - - "traefik.http.services.erpnext-nginx.loadbalancer.server.port=80" + - "traefik.http.services.erpnext-nginx.loadbalancer.server.port=8080" erpnext-python: image: frappe/erpnext-worker:${ERPNEXT_VERSION?Variable ERPNEXT_VERSION not set} diff --git a/frappe-installer b/frappe-installer deleted file mode 100755 index e379f84bba..0000000000 --- a/frappe-installer +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -IFS=$'\n\t' - -[[ -z "${DEBUG}" && "${DEBUG}" == 1 ]] && set -o xtrace - -__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$__dir" - -env_url="https://raw.githubusercontent.com/frappe/frappe_docker/master/installation/env-example" -docker_nginx_url="https://github.com/evertramos/docker-compose-letsencrypt-nginx-proxy-companion" -frappe_docker_url="https://github.com/frappe/frappe_docker" -env_file="$__dir/.env" - -function check_root() { - if [[ $EUID != 0 ]]; then - echo "This script must be run as root. Login as root or use sudo." >&2 - exit 1 - fi -} - -function check_git() { - if [[ ! -x "$(command -v git)" ]]; then - echo "Git is not installed. Please install git before continuing." >&2 - exit 1 - fi -} - -function check_docker() { - if [[ ! -x "$(command -v docker)" ]]; then - read -rp "No docker installation found. Press Enter to install docker or ctrl+c to exit." >&2 - curl -fsSL https://get.docker.com | sh - fi - if [[ ! -x "$(command -v docker)" ]]; then - echo "Docker installation failed. Exiting." >&2 - exit 1 - fi -} - -function check_env() { - if [[ ! -f "$env_file" ]]; then - cat <&2 - No environment file found. This file is required for setting up Frappe/ERPNext Docker. - Would you like to fetch the default environment file? - (NOTE: You will be prompted to set it up later) -CHOOSE - read -rp "Press Enter to fetch the configuration file, or create a .env file and re-run the script." - curl -fsSL "$env_url" -o "$env_file" - fi -} - -function clone_repository() { - echo "Cloning Repository: $1" - git clone "$2" -} - -function get_config() { - if [[ -n "$2" ]]; then - config_file="$2" - else - config_file="$env_file" - fi - line=$(grep -E "^$=" "$config_file") - line_result=$(echo "$line" | awk -F"=" '{print $2}') -} - -function get_install_version() { - cat <&2 - Choose a version you would like to setup [current: $1]: - 1. develop (edge) - 2. version-12 - 3. version-11 - Please enter your choice [1-3]: -CHOOSE - select choice in "1" "2" "3"; do - case ${choice} in - 1) version="edge" ;; - 2) version="version-12" ;; - 3) version="version-11" ;; - esac - done -} - -function prompt_config() { - # inspired by discourse_docker - get_config "VERSION" - local install_version=$line_result - get_config "MYSQL_ROOT_PASSWORD" - local mysql_password=$line_result - get_config "SITES" - local sites=$line_result - get_config "LETSENCRYPT_EMAIL" - local letsencrypt_email=$line_result - - echo "Would you like to setup networking for docker? [y/n]" - echo "This is required if you wish to access the instance from other machines." - select choice in "y" "n"; do - case $choice in - y) setup_networking=1 ;; - n) - setup_networking=0 - setup_letsencrypt=0 - ;; - esac - done - if [[ -n "$letsencrypt_email" && "$setup_networking" -ne "0" ]]; then - echo "Would you like to setup LetsEncrypt? [y/n]" - select choice in "y" "n"; do - case $choice in - y) - setup_letsencrypt=1 - echo "Please ensure that all the required domains point to this IP address." - read -rp "Enter an Email Address to setup LetsEncrypt with: " letsencrypt_email - ;; - n) - setup_letsencrypt=0 - echo "Skipping LetsEncrypt Setup." - ;; - esac - done - fi - - local new_value="" - local config_state="n" - - echo - - get_install_version "$install_version" - install_version="$version" - - while [[ "$config_state" == "n" ]]; do - if [[ -n "$mysql_password" ]]; then - read -srp "Enter MySQL Password [$mysql_password]: " new_value - if [[ -n "$new_value" ]]; then - mysql_password="$new_value" - fi - fi - - if [[ -n "$sites" ]]; then - read -rp "Enter sitename to setup [$sites]: " new_value - if [[ -n "$new_value" ]]; then - sites="$new_value" - fi - fi - - if [[ "$setup_letsencrypt" != "0" ]]; then - read -rp "Enter email address for LetsEncrypt [$letsencrypt_email]: " new_value - if [[ -n "$new_value" ]]; then - letsencrypt_email=$new_value - fi - fi - - echo "Current Configuration:" - echo "Version: $([[ "$install_version" == "edge" ]] && echo "develop" || echo "$install_version")" - echo "MySQL Root Password: $mysql_password" - echo "Sites: $sites" - - if [[ "$setup_letsencrypt" != "0" ]]; then - echo "LetsEncrypt Email Address: $letsencrypt_email" - fi - - echo - echo "Does this configuration look okay?" - read -rp "Press Enter to continue, 'n' to try again, or ctrl+c to exit: " config_state - done - - echo "Saving the current configuration file to $env_file" - - cat <"$env_file" -VERSION=$install_version -MYSQL_ROOT_PASSWORD=$mysql_password -SITES=$sites -$([ "$setup_letsencrypt" -ne "0" ] && echo "LETSENCRYPT_EMAIL=$letsencrypt_email") -EOF - setup_configuration=$(<"$env_file") -} - -setup_user() { - echo "The rest of the setup requires a user account." - echo "You may use an existing account, or set up a new one right away." - read -rp "Enter username: " username - if grep -E "^$username" /etc/passwd >/dev/null; then - echo "User $username already exists." - else - read -rsp "Enter password: " password - password="$(perl -e 'print crypt($ARGV[0], "password")' "$password")" - if useradd -m -p "$password" "$username" -s "$(command -v bash)"; then - echo "User $username has been added to the system." - else - echo "Failed to add user to the system." - echo "Please add a user manually and re-run the script." - exit 1 - fi - fi - - if ! getent group docker >/dev/null 2>&1; then - echo "Creating group: docker" - groupadd docker - fi - echo "Adding user $username to group: docker" - usermod -aG docker "$username" - newgrp docker -} - -install() { - if [[ "$setup_letsencrypt" != "0" && "$setup_networking" != "0" ]]; then - echo "Setting up NGINX Proxy for LetsEncrypt" - clone_repository "Docker Compose LetsEncrypt NGINX Proxy Companion" "$docker_nginx_url" - cd "$(basename "$docker_nginx_url")" - if [[ -f .env.sample ]]; then - cp .env.sample env - fi - ./start.sh >/dev/null 2>&1 - cd "$(eval echo ~"$username")" - fi - - echo "Setting up Frappe/ERPNext" - clone_repository "Frappe/ERPNext Docker" "$frappe_docker_url" - cd "$(basename "$frappe_docker_url")" - echo "$setup_configuration" >.env - echo "Enter a name for the project." - read -rp "This project name will be used to setup the docker instance: [erpnext_docker]" project_name - if [[ -z "$project_name" ]]; then - echo "Setting the project name to erpnext_docker" - project_name="erpnext_docker" - fi - - docker-compose \ - --project-name "$project_name" \ - --project-directory . up -d \ - -f installation/docker-compose-frappe.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/docker-compose-common.yml \ - "$( ((setup_networking == 1)) && printf %s '-f installation/docker-compose-networks.yml')" - - get_config "SITES" "$(pwd)/.env" - local sites=$line_result - - docker exec \ - -e "SITE_NAME=$sites" \ - -e "INSTALL_ERPNEXT=1" \ - -it "$project_name"_erpnext-python_1 docker-entrypoint.sh new - - echo "Installation Complete!" -} - -check_root -check_git -check_docker -check_env - -prompt_config -setup_user -install diff --git a/installation/docker-compose-frappe.yml b/installation/docker-compose-frappe.yml index afd661bf58..5c64424e5f 100644 --- a/installation/docker-compose-frappe.yml +++ b/installation/docker-compose-frappe.yml @@ -117,4 +117,4 @@ services: volumes: assets-vol: sites-vol: - logs-vol: \ No newline at end of file + logs-vol: diff --git a/installation/erpnext-publish.yml b/installation/erpnext-publish.yml index 6975442a41..130c52b6b0 100644 --- a/installation/erpnext-publish.yml +++ b/installation/erpnext-publish.yml @@ -3,4 +3,4 @@ version: "3" services: erpnext-nginx: ports: - - "80:80" + - "80:8080" diff --git a/installation/frappe-postgresql/docker-compose.yml b/installation/frappe-postgresql/docker-compose.yml index 8f479aa22e..c36bdb056a 100644 --- a/installation/frappe-postgresql/docker-compose.yml +++ b/installation/frappe-postgresql/docker-compose.yml @@ -42,7 +42,7 @@ services: - "traefik.http.routers.frappe-nginx.rule=Host(${SITES})" - "${ENTRYPOINT_LABEL}" - "${CERT_RESOLVER_LABEL}" - - "traefik.http.services.frappe-nginx.loadbalancer.server.port=80" + - "traefik.http.services.frappe-nginx.loadbalancer.server.port=8080" volumes: - sites-vol:/var/www/html/sites:rw - assets-vol:/assets:rw diff --git a/installation/frappe-publish.yml b/installation/frappe-publish.yml index a3f4caa9f6..f573cb79aa 100644 --- a/installation/frappe-publish.yml +++ b/installation/frappe-publish.yml @@ -3,4 +3,4 @@ version: "3" services: frappe-nginx: ports: - - "80:80" + - "80:8080" diff --git a/tests/check-format.sh b/tests/check-format.sh deleted file mode 100755 index 144984b32a..0000000000 --- a/tests/check-format.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -echo "Checking bash scripts with shellcheck" >&2 - -while IFS= read -r shellfile; do - shellcheck --check-sourced --severity=style --color=always --exclude=SC2164,SC2086,SC2012,SC2016 ${shellfile} -done < <(find ./build -name "*.sh") diff --git a/tests/docker-test.sh b/tests/docker-test.sh deleted file mode 100755 index 5b917f2147..0000000000 --- a/tests/docker-test.sh +++ /dev/null @@ -1,400 +0,0 @@ -#!/bin/bash -ULINE='\e[1m\e[4m' -ENDULINE='\e[0m' -NEWLINE='\n' - -function checkMigrationComplete() { - echo "Check Migration" - CONTAINER_ID=$(docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - ps -q erpnext-python) - - DOCKER_LOG=$(docker logs ${CONTAINER_ID} 2>&1 | grep "Starting gunicorn") - INCREMENT=0 - while [[ ${DOCKER_LOG} != *"Starting gunicorn"* && ${INCREMENT} -lt 60 ]]; do - sleep 3 - echo "Wait for migration to complete ..." - ((INCREMENT = INCREMENT + 1)) - DOCKER_LOG=$(docker logs ${CONTAINER_ID} 2>&1 | grep "Starting gunicorn") - if [[ ${DOCKER_LOG} != *"Starting gunicorn"* && ${INCREMENT} -eq 60 ]]; then - docker logs ${CONTAINER_ID} - exit 1 - fi - done - - echo -e "${ULINE}Migration Log${ENDULINE}" - docker logs ${CONTAINER_ID} -} - -function loopHealthCheck() { - echo "Create Container to Check MariaDB" - docker run --name frappe_doctor \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge doctor || true - - echo "Loop Health Check" - FRAPPE_LOG=$(docker logs frappe_doctor | grep "Health check successful" || echo "") - while [[ -z "${FRAPPE_LOG}" ]]; do - sleep 1 - CONTAINER=$(docker start frappe_doctor) - echo "Restarting ${CONTAINER} ..." - FRAPPE_LOG=$(docker logs frappe_doctor | grep "Health check successful" || echo "") - done - echo "Health check successful" -} - -echo -e "${ULINE}Copy env-example file${ENDULINE}" -cp env-example .env - -echo -e "${NEWLINE}${ULINE}Set version to v13${ENDULINE}" -sed -i -e "s/edge/v13/g" .env - -echo -e "${NEWLINE}${ULINE}Start Services${ENDULINE}" -docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - pull -docker pull postgres:11.8 -docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - up -d -# Start postgres -docker run --name postgresql -d \ - -e "POSTGRES_PASSWORD=admin" \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - postgres:11.8 - -loopHealthCheck - -echo -e "${NEWLINE}${ULINE}Create new site (v13)${ENDULINE}" -docker run -it \ - -e "SITE_NAME=test.localhost" \ - -e "INSTALL_APPS=erpnext" \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:v13 new - -echo -e "${NEWLINE}${ULINE}Ping created site${ENDULINE}" -curl -sS http://test.localhost/api/method/version - -echo -e "${NEWLINE}${ULINE}Check Created Site Index Page${ENDULINE}" -curl -s http://test.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Set version to edge${ENDULINE}" -sed -i -e "s/v13/edge/g" .env - -echo -e "${NEWLINE}${ULINE}Restart containers with edge image${ENDULINE}" -docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - stop -docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - up -d - -checkMigrationComplete - -echo -e "${NEWLINE}${ULINE}Ping migrated site${ENDULINE}" -sleep 3 -curl -sS http://test.localhost/api/method/version - -echo -e "${NEWLINE}${ULINE}Check Migrated Site Index Page${ENDULINE}" -curl -s http://test.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Create new site (pgsql)${ENDULINE}" -docker run -it \ - -e "SITE_NAME=pgsql.localhost" \ - -e "POSTGRES_HOST=postgresql" \ - -e "DB_ROOT_USER=postgres" \ - -e "POSTGRES_PASSWORD=admin" \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge new - -echo -e "${NEWLINE}${ULINE}Check New PGSQL Site${ENDULINE}" -sleep 3 -RESTORE_STATUS=$(curl -sS http://pgsql.localhost/api/method/version || echo "") -INCREMENT=0 -while [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -lt 60 ]]; do - sleep 1 - echo -e "${ULINE}Wait for restoration to complete ..." - RESTORE_STATUS=$(curl -sS http://pgsql.localhost/api/method/version || echo "") - ((INCREMENT = INCREMENT + 1)) - if [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -eq 60 ]]; then - CONTAINER_ID=$(docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - ps -q erpnext-python) - docker logs ${CONTAINER_ID} - exit 1 - fi -done - -echo -e "${NEWLINE}${ULINE}Ping new pgsql site${ENDULINE}" -echo $RESTORE_STATUS - -echo -e "${NEWLINE}${ULINE}Check New PGSQL Index Page${ENDULINE}" -curl -s http://pgsql.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Backup site${ENDULINE}" -docker run -it \ - -e "WITH_FILES=1" \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge backup - -MINIO_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE" -MINIO_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" - -echo -e "${ULINE}Start MinIO container for s3 compatible storage${ENDULINE}" -docker run -d --name minio \ - -e "MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}" \ - -e "MINIO_SECRET_KEY=${MINIO_SECRET_KEY}" \ - --network frappebench00_default \ - minio/minio server /data - -echo -e "${NEWLINE}${ULINE}Create bucket named erpnext${ENDULINE}" -docker run \ - --network frappebench00_default \ - vltgroup/s3cmd:latest s3cmd --access_key=${MINIO_ACCESS_KEY} \ - --secret_key=${MINIO_SECRET_KEY} \ - --region=us-east-1 \ - --no-ssl \ - --host=minio:9000 \ - --host-bucket=minio:9000 \ - mb s3://erpnext - -echo -e "${NEWLINE}${NEWLINE}${ULINE}Push backup to MinIO s3${ENDULINE}" -docker run \ - -e BUCKET_NAME=erpnext \ - -e REGION=us-east-1 \ - -e BUCKET_DIR=local \ - -e ACCESS_KEY_ID=${MINIO_ACCESS_KEY} \ - -e SECRET_ACCESS_KEY=${MINIO_SECRET_KEY} \ - -e ENDPOINT_URL=http://minio:9000 \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge push-backup - -echo -e "${NEWLINE}${ULINE}Stop Services${ENDULINE}" -docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - stop - -echo -e "${NEWLINE}${ULINE}Prune Containers${ENDULINE}" -docker container prune -f && docker volume prune -f - -echo -e "${NEWLINE}${ULINE}Start Services${ENDULINE}" -docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - up -d - -loopHealthCheck - -echo -e "${NEWLINE}${ULINE}Restore backup from MinIO / S3${ENDULINE}" -docker run \ - -e MYSQL_ROOT_PASSWORD=admin \ - -e BUCKET_NAME=erpnext \ - -e BUCKET_DIR=local \ - -e ACCESS_KEY_ID=${MINIO_ACCESS_KEY} \ - -e SECRET_ACCESS_KEY=${MINIO_SECRET_KEY} \ - -e ENDPOINT_URL=http://minio:9000 \ - -e REGION=us-east-1 \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge restore-backup - -echo -e "${NEWLINE}${ULINE}Check Restored Site (test)${ENDULINE}" -sleep 3 -RESTORE_STATUS=$(curl -sS http://test.localhost/api/method/version || echo "") -INCREMENT=0 -while [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -lt 60 ]]; do - sleep 1 - echo "Wait for restoration to complete ..." - RESTORE_STATUS=$(curl -sS http://test.localhost/api/method/version || echo "") - ((INCREMENT = INCREMENT + 1)) - if [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -eq 60 ]]; then - CONTAINER_ID=$(docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - ps -q erpnext-python) - docker logs ${CONTAINER_ID} - exit 1 - fi -done - -echo -e "${ULINE}Ping restored site (test)${ENDULINE}" -echo ${RESTORE_STATUS} - -echo -e "${NEWLINE}${ULINE}Check Restored Site Index Page (test)${ENDULINE}" -curl -s http://test.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Check Restored Site (pgsql)${ENDULINE}" -sleep 3 -RESTORE_STATUS=$(curl -sS http://pgsql.localhost/api/method/version || echo "") -INCREMENT=0 -while [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -lt 60 ]]; do - sleep 1 - echo "Wait for restoration to complete ..." - RESTORE_STATUS=$(curl -sS http://pgsql.localhost/api/method/version || echo "") - ((INCREMENT = INCREMENT + 1)) - if [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -eq 60 ]]; then - CONTAINER_ID=$(docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - ps -q erpnext-python) - docker logs ${CONTAINER_ID} - exit 1 - fi -done - -echo -e "${ULINE}Ping restored site (pgsql)${ENDULINE}" -echo ${RESTORE_STATUS} - -echo -e "${NEWLINE}${ULINE}Check Restored Site Index Page (pgsql)${ENDULINE}" -curl -s http://pgsql.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Create new site (edge)${ENDULINE}" -docker run -it \ - -e "SITE_NAME=edge.localhost" \ - -e "INSTALL_APPS=erpnext" \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge new - -echo -e "${NEWLINE}${ULINE}Check New Edge Site${ENDULINE}" -sleep 3 -RESTORE_STATUS=$(curl -sS http://edge.localhost/api/method/version || echo "") -INCREMENT=0 -while [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -lt 60 ]]; do - sleep 1 - echo -e "${ULINE}Wait for restoration to complete ...${ENDULINE}" - RESTORE_STATUS=$(curl -sS http://edge.localhost/api/method/version || echo "") - ((INCREMENT = INCREMENT + 1)) - if [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -eq 60 ]]; then - CONTAINER_ID=$(docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - ps -q erpnext-python) - docker logs ${CONTAINER_ID} - exit 1 - fi -done - -echo -e "${NEWLINE}${ULINE}Ping new edge site${ENDULINE}" -echo ${RESTORE_STATUS} - -echo -e "${NEWLINE}${ULINE}Check New Edge Index Page${ENDULINE}" -curl -s http://edge.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Migrate command in edge container${ENDULINE}" -docker run -it \ - -e "MAINTENANCE_MODE=1" \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - -v frappebench00_assets-vol:/home/frappe/frappe-bench/sites/assets \ - --network frappebench00_default \ - frappe/erpnext-worker:edge migrate - -checkMigrationComplete - -echo -e "${NEWLINE}${ULINE}Restore backup from MinIO / S3 (Overwrite)${ENDULINE}" -docker run \ - -e MYSQL_ROOT_PASSWORD=admin \ - -e BUCKET_NAME=erpnext \ - -e BUCKET_DIR=local \ - -e ACCESS_KEY_ID=${MINIO_ACCESS_KEY} \ - -e SECRET_ACCESS_KEY=${MINIO_SECRET_KEY} \ - -e ENDPOINT_URL=http://minio:9000 \ - -e REGION=us-east-1 \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge restore-backup - -echo -e "${NEWLINE}${ULINE}Check Overwritten Site${ENDULINE}" -sleep 3 -RESTORE_STATUS=$(curl -sS http://test.localhost/api/method/version || echo "") -INCREMENT=0 -while [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -lt 60 ]]; do - sleep 1 - echo -e "${ULINE}Wait for restoration to complete ..." - RESTORE_STATUS=$(curl -sS http://test.localhost/api/method/version || echo "") - ((INCREMENT = INCREMENT + 1)) - if [[ -z "${RESTORE_STATUS}" && ${INCREMENT} -eq 60 ]]; then - CONTAINER_ID=$(docker-compose \ - --project-name frappebench00 \ - -f installation/docker-compose-common.yml \ - -f installation/docker-compose-erpnext.yml \ - -f installation/erpnext-publish.yml \ - ps -q erpnext-python) - docker logs ${CONTAINER_ID} - exit 1 - fi -done - -echo -e "${NEWLINE}${ULINE}Ping overwritten site${ENDULINE}" -echo ${RESTORE_STATUS} - -echo -e "${NEWLINE}${ULINE}Check Overwritten Index Page${ENDULINE}" -curl -s http://test.localhost | w3m -T text/html -dump - -echo -e "${NEWLINE}${ULINE}Check console command for site test.localhost${ENDULINE}" -docker run \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge console test.localhost - -echo -e "${NEWLINE}${ULINE}Check console command for site pgsql.localhost${ENDULINE}" -docker run \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge console pgsql.localhost - -echo -e "${NEWLINE}${ULINE}Check drop site: test.localhost (mariadb)${ENDULINE}" -docker run \ - -e SITE_NAME=test.localhost \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge drop - -echo -e "${NEWLINE}${ULINE}Check drop site: pgsql.localhost (pgsql)${ENDULINE}" -docker run \ - -e SITE_NAME=pgsql.localhost \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - frappe/erpnext-worker:edge drop - -echo -e "${NEWLINE}${ULINE}Check bench --help${ENDULINE}" -docker run \ - -v frappebench00_sites-vol:/home/frappe/frappe-bench/sites \ - --network frappebench00_default \ - --user frappe \ - frappe/erpnext-worker:edge bench --help diff --git a/tests/functions.sh b/tests/functions.sh new file mode 100644 index 0000000000..8453c499ab --- /dev/null +++ b/tests/functions.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +print_group() { + echo ::endgroup:: + echo "::group::$*" +} + +ping_site() { + print_group "Ping site $SITE_NAME" + + echo Ping version + ping_res=$(curl -sS "http://$SITE_NAME/api/method/version") + echo "$ping_res" + if [[ -z $(echo "$ping_res" | grep "message" || echo "") ]]; then + echo "Ping failed" + exit 1 + fi + + echo Check index + index_res=$(curl -sS "http://$SITE_NAME") + if [[ -n $(echo "$index_res" | grep "Internal Server Error" || echo "") ]]; then + echo "Index check failed" + echo "$index_res" + exit 1 + fi +} diff --git a/tests/integration-test.sh b/tests/integration-test.sh new file mode 100755 index 0000000000..af7a8831ad --- /dev/null +++ b/tests/integration-test.sh @@ -0,0 +1,283 @@ +#!/bin/bash + +set -e + +source tests/functions.sh + +project_name=frappe_bench_00 + +docker_compose_with_args() { + # shellcheck disable=SC2068 + docker-compose \ + -p $project_name \ + -f installation/docker-compose-common.yml \ + -f installation/docker-compose-frappe.yml \ + -f installation/frappe-publish.yml \ + $@ +} + +check_migration_complete() { + print_group Check migration + + container_id=$(docker_compose_with_args ps -q frappe-python) + cmd="docker logs ${container_id} 2>&1 | grep 'Starting gunicorn' || echo ''" + worker_log=$(eval "$cmd") + INCREMENT=0 + + while [[ ${worker_log} != *"Starting gunicorn"* && ${INCREMENT} -lt 120 ]]; do + sleep 3 + ((INCREMENT = INCREMENT + 1)) + echo "Wait for migration to complete..." + worker_log=$(eval "$cmd") + if [[ ${worker_log} != *"Starting gunicorn"* && ${INCREMENT} -eq 120 ]]; then + echo Migration timeout + docker logs "${container_id}" + exit 1 + fi + done + + echo Migration Log + docker logs "${container_id}" +} + +check_health() { + print_group Loop health check + + docker run --name frappe_doctor \ + -v "${project_name}_sites-vol:/home/frappe/frappe-bench/sites" \ + --network "${project_name}_default" \ + frappe/frappe-worker:edge doctor || true + + cmd='docker logs frappe_doctor | grep "Health check successful" || echo ""' + doctor_log=$(eval "$cmd") + INCREMENT=0 + + while [[ -z "${doctor_log}" && ${INCREMENT} -lt 60 ]]; do + sleep 1 + ((INCREMENT = INCREMENT + 1)) + container=$(docker start frappe_doctor) + echo "Restarting ${container}..." + doctor_log=$(eval "$cmd") + + if [[ ${INCREMENT} -eq 60 ]]; then + docker logs "${container}" + exit 1 + fi + done +} + +# Initial group +echo ::group::Setup .env +cp env-example .env +sed -i -e "s/edge/v13/g" .env +cat .env +# shellcheck disable=SC2046 +export $(cat .env) + +print_group Start services +echo Start main services +docker_compose_with_args up -d --quiet-pull + +echo Start postgres +docker pull postgres:11.8 -q +docker run \ + --name postgresql \ + -d \ + -e POSTGRES_PASSWORD=admin \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + postgres:11.8 + +check_health + +print_group "Create new site " +SITE_NAME=test.localhost +docker run \ + --rm \ + -e SITE_NAME=$SITE_NAME \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:v13 new + +ping_site + +print_group "Update .env (v13 -> edge)" +sed -i -e "s/v13/edge/g" .env +cat .env +# shellcheck disable=SC2046 +export $(cat .env) + +print_group Restart containers +docker_compose_with_args stop +docker_compose_with_args up -d + +check_migration_complete +sleep 5 +ping_site + +PG_SITE_NAME=pgsql.localhost +print_group "Create new site (Postgres)" +docker run \ + --rm \ + -e SITE_NAME=$PG_SITE_NAME \ + -e POSTGRES_HOST=postgresql \ + -e DB_ROOT_USER=postgres \ + -e POSTGRES_PASSWORD=admin \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge new + +check_migration_complete +SITE_NAME=$PG_SITE_NAME ping_site + +print_group Backup site +docker run \ + --rm \ + -e WITH_FILES=1 \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge backup + +MINIO_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE" +MINIO_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + +print_group Prepare S3 server +echo Start S3 server +docker run \ + --name minio \ + -d \ + -e "MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY" \ + -e "MINIO_SECRET_KEY=$MINIO_SECRET_KEY" \ + --network ${project_name}_default \ + minio/minio server /data + +echo Create bucket +docker run \ + --rm \ + --network ${project_name}_default \ + vltgroup/s3cmd:latest \ + s3cmd \ + --access_key=$MINIO_ACCESS_KEY \ + --secret_key=$MINIO_SECRET_KEY \ + --region=us-east-1 \ + --no-ssl \ + --host=minio:9000 \ + --host-bucket=minio:9000 \ + mb s3://frappe + +print_group Push backup +docker run \ + --rm \ + -e BUCKET_NAME=frappe \ + -e REGION=us-east-1 \ + -e BUCKET_DIR=local \ + -e ACCESS_KEY_ID=$MINIO_ACCESS_KEY \ + -e SECRET_ACCESS_KEY=$MINIO_SECRET_KEY \ + -e ENDPOINT_URL=http://minio:9000 \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge push-backup + +print_group Prune and restart services +docker_compose_with_args stop +docker container prune -f && docker volume prune -f +docker_compose_with_args up -d + +check_health + +print_group Restore backup from S3 +docker run \ + --rm \ + -e MYSQL_ROOT_PASSWORD=admin \ + -e BUCKET_NAME=frappe \ + -e BUCKET_DIR=local \ + -e ACCESS_KEY_ID=$MINIO_ACCESS_KEY \ + -e SECRET_ACCESS_KEY=$MINIO_SECRET_KEY \ + -e ENDPOINT_URL=http://minio:9000 \ + -e REGION=us-east-1 \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge restore-backup + +check_health +ping_site +SITE_NAME=$PG_SITE_NAME ping_site + +EDGE_SITE_NAME=edge.localhost +print_group "Create new site (edge)" +docker run \ + --rm \ + -e SITE_NAME=$EDGE_SITE_NAME \ + -e INSTALL_APPS=frappe \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge new + +check_health +SITE_NAME=$EDGE_SITE_NAME ping_site + +print_group Migrate edge site +docker run \ + --rm \ + -e MAINTENANCE_MODE=1 \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + -v ${project_name}_assets-vol:/home/frappe/frappe-bench/sites/assets \ + --network ${project_name}_default \ + frappe/frappe-worker:edge migrate + +check_migration_complete + +print_group "Restore backup S3 (overwrite)" +docker run \ + --rm \ + -e MYSQL_ROOT_PASSWORD=admin \ + -e BUCKET_NAME=frappe \ + -e BUCKET_DIR=local \ + -e ACCESS_KEY_ID=$MINIO_ACCESS_KEY \ + -e SECRET_ACCESS_KEY=$MINIO_SECRET_KEY \ + -e ENDPOINT_URL=http://minio:9000 \ + -e REGION=us-east-1 \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge restore-backup + +check_migration_complete +ping_site + +print_group "Check console for $SITE_NAME" +docker run \ + --rm \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge console $SITE_NAME + +print_group "Check console for $PG_SITE_NAME" +docker run \ + --rm \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge console $PG_SITE_NAME + +print_group "Check drop site for $SITE_NAME (MariaDB)" +docker run \ + --rm \ + -e SITE_NAME=$SITE_NAME \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge drop + +print_group "Check drop site for $PG_SITE_NAME (Postgres)" +docker run \ + --rm \ + -e SITE_NAME=$PG_SITE_NAME \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:edge drop + +print_group Check bench --help +docker run \ + --rm \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + --user frappe \ + frappe/frappe-worker:edge bench --help diff --git a/tests/pwd.yml b/tests/pwd.yml index d4cb3550c4..339900ccf3 100644 --- a/tests/pwd.yml +++ b/tests/pwd.yml @@ -37,7 +37,7 @@ services: - "traefik.http.middlewares.erpnext-nginx.headers.customrequestheaders.Host=erpnext-nginx" - "traefik.http.routers.erpnext-nginx.middlewares=erpnext-nginx" - "traefik.http.routers.erpnext-nginx.entrypoints=web" - - "traefik.http.services.erpnext-nginx.loadbalancer.server.port=80" + - "traefik.http.services.erpnext-nginx.loadbalancer.server.port=8080" volumes: - sites-vol:/var/www/html/sites:rw - assets-vol:/assets:rw diff --git a/tests/test-erpnext.sh b/tests/test-erpnext.sh new file mode 100755 index 0000000000..a22d999b87 --- /dev/null +++ b/tests/test-erpnext.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +set -e + +source tests/functions.sh + +project_name="test_erpnext" +SITE_NAME="test_erpnext.localhost" + +echo ::group::Setup env +cp env-example .env +sed -i -e "s/FRAPPE_VERSION=edge/FRAPPE_VERSION=$FRAPPE_VERSION/g" .env +sed -i -e "s/ERPNEXT_VERSION=edge/ERPNEXT_VERSION=test/g" .env +# shellcheck disable=SC2046 +export $(cat .env) +cat .env + +print_group Start services +FRAPPE_VERSION=$FRAPPE_VERSION ERPNEXT_VERSION="test" \ + docker-compose \ + -p $project_name \ + -f installation/docker-compose-common.yml \ + -f installation/docker-compose-erpnext.yml \ + -f installation/erpnext-publish.yml \ + up -d + +docker run \ + --rm \ + --user root \ + -v ${project_name}_sites-vol:/sites \ + -v ${project_name}_assets-vol:/assets \ + -v ${project_name}_logs-vol:/logs \ + frappe/erpnext-worker:test chown -R 1000:1000 /logs /sites /assets + +print_group Create site +docker run \ + --rm \ + -e "SITE_NAME=$SITE_NAME" \ + -e "INSTALL_APPS=erpnext" \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/erpnext-worker:test new + +ping_site +rm .env diff --git a/tests/test-frappe.sh b/tests/test-frappe.sh new file mode 100755 index 0000000000..c28e0cfd9d --- /dev/null +++ b/tests/test-frappe.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -e + +source tests/functions.sh + +project_name="test_frappe" +SITE_NAME="test_frappe.localhost" + +echo ::group::Setup env +cp env-example .env +sed -i -e "s/edge/test/g" .env +# shellcheck disable=SC2046 +export $(cat .env) +cat .env + +print_group Start services +FRAPPE_VERSION="test" \ + docker-compose \ + -p $project_name \ + -f installation/docker-compose-common.yml \ + -f installation/docker-compose-frappe.yml \ + -f installation/frappe-publish.yml \ + up -d + +print_group Create site +docker run \ + --rm \ + -e "SITE_NAME=$SITE_NAME" \ + -v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \ + --network ${project_name}_default \ + frappe/frappe-worker:test new + +ping_site +rm .env diff --git a/travis.py b/travis.py deleted file mode 100755 index bff2d3b47f..0000000000 --- a/travis.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import subprocess -import os - - -def parse_args(): - parser = argparse.ArgumentParser( - description="frappe_docker common CI elements", add_help=True - ) - - parser.add_argument( - "service", - action="store", - type=str, - help='Name of the service to build: "erpnext" or "frappe"', - ) - parser.add_argument( - "-o", - "--tag-only", - required=False, - action="store_true", - dest="tag_only", - help="Only tag an image and push it.", - ) - parser.add_argument( - "-b", - "--is-beta", - required=False, - default=False, - action="store_true", - dest="is_beta", - help="Specify if tag is beta", - ) - - image_type = parser.add_mutually_exclusive_group(required=True) - image_type.add_argument( - "-a", - "--nginx", - action="store_const", - dest="image_type", - const="nginx", - help="Build the nginx + static assets image", - ) - image_type.add_argument( - "-s", - "--socketio", - action="store_const", - dest="image_type", - const="socketio", - help="Build the frappe-socketio image", - ) - image_type.add_argument( - "-w", - "--worker", - action="store_const", - dest="image_type", - const="worker", - help="Build the python environment image", - ) - - tag_type = parser.add_mutually_exclusive_group(required=True) - tag_type.add_argument( - "-g", - "--git-version", - action="store", - type=str, - dest="version", - help='The version number of service (i.e. "11", "12", etc.)', - ) - tag_type.add_argument( - "-t", - "--tag", - action="store", - type=str, - dest="tag", - help="The image tag (i.e. erpnext-worker:$TAG )", - ) - - args = parser.parse_args() - return args - - -def git_version(service, version, branch, is_beta=False): - print(f"Pulling {service} v{version}") - subprocess.run( - f"git clone https://github.com/frappe/{service} --branch {branch}", shell=True - ) - cd = os.getcwd() - os.chdir(os.getcwd() + f"/{service}") - subprocess.run("git fetch --tags", shell=True) - - # XX-beta becomes XX for tags search - version = version.split("-")[0] - - version_tag = ( - subprocess.check_output( - f"git tag --list --sort=-version:refname \"v{version}*\" | sed -n 1p | sed -e 's#.*@\(\)#\\1#'", - shell=True, - ) - .strip() - .decode("ascii") - ) - - if not is_beta: - version_tag = version_tag.split("-")[0] - - os.chdir(cd) - return version_tag - - -def build(service, tag, image, branch): - build_args = f"--build-arg GIT_BRANCH={branch}" - if service == "erpnext": - build_args += f" --build-arg IMAGE_TAG={branch}" - if image == "nginx" and branch == "version-11": - build_args += f" --build-arg NODE_IMAGE_TAG=10-prod" - - print(f"Building {service} {image} image") - subprocess.run( - f"docker build {build_args} -t {service}-{image} -f build/{service}-{image}/Dockerfile .", - shell=True, - ) - tag_and_push(f"{service}-{image}", tag) - - -def tag_and_push(image_name, tag): - print(f'Tagging {image_name} as "{tag}" and pushing') - subprocess.run(f"docker tag {image_name} frappe/{image_name}:{tag}", shell=True) - subprocess.run(f"docker push frappe/{image_name}:{tag}", shell=True) - - -def main(): - args = parse_args() - tag = args.tag - branch = "develop" - - if args.version: - branch = "version-" + args.version - tag = git_version(args.service, args.version, branch, args.is_beta) - - if args.tag_only: - tag_and_push(f"{args.service}-{args.image_type}", tag) - else: - build(args.service, tag, args.image_type, branch) - - -if __name__ == "__main__": - main()