diff --git a/docker/.env b/.env similarity index 89% rename from docker/.env rename to .env index 54e37ea7a0..586b0daab3 100644 --- a/docker/.env +++ b/.env @@ -1,4 +1,5 @@ # InvenTree environment variables for a development setup +# These variables will be used by the docker-compose.yml file # Set DEBUG to True for a development setup INVENTREE_DEBUG=True diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..e87a705e10 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +# General owner is the maintainers team +* @SchrodingersGat + +# plugins are co-owned +/InvenTree/plugin/ @SchrodingersGat @matmair +/InvenTree/plugins/ @SchrodingersGat @matmair diff --git a/.github/actions/migration/action.yaml b/.github/actions/migration/action.yaml new file mode 100644 index 0000000000..3270a9e55b --- /dev/null +++ b/.github/actions/migration/action.yaml @@ -0,0 +1,17 @@ +name: 'Migration test' +description: 'Run migration test sequenze' +author: 'inventree' + +runs: + using: 'composite' + steps: + - name: Data Import Export + shell: bash + run: | + invoke migrate + invoke import-fixtures + invoke export-records -f data.json + python3 ./InvenTree/manage.py flush --noinput + invoke migrate + invoke import-records -f data.json + invoke import-records -f data.json diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml new file mode 100644 index 0000000000..1a954349ef --- /dev/null +++ b/.github/actions/setup/action.yaml @@ -0,0 +1,82 @@ +name: 'Setup Enviroment' +description: 'Setup the enviroment for general InvenTree tests' +author: 'inventree' +inputs: + python: + required: false + description: 'Install python.' + default: 'true' + npm: + required: false + description: 'Install npm.' + default: 'false' + + install: + required: false + description: 'Install the InvenTree requirements?' + default: 'false' + update: + required: false + description: 'Should a full update cycle be run?' + default: 'false' + + apt-dependency: + required: false + description: 'Extra APT package for install.' + pip-dependency: + required: false + description: 'Extra python package for install.' + +runs: + using: 'composite' + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + # Python installs + - name: Set up Python ${{ env.python_version }} + if: ${{ inputs.python == 'true' }} + uses: actions/setup-python@v2 + with: + python-version: ${{ env.python_version }} + cache: pip + - name: Install Base Python Dependencies + if: ${{ inputs.python == 'true' }} + shell: bash + run: | + python3 -m pip install -U pip + pip3 install invoke wheel + - name: Install Specific Python Dependencies + if: ${{ inputs.pip-dependency }} + shell: bash + run: pip3 install ${{ inputs.pip-dependency }} + + # NPM installs + - name: Install node.js ${{ env.node_version }} + if: ${{ inputs.npm == 'true' }} + uses: actions/setup-node@v2 + with: + node-version: ${{ env.node_version }} + cache: 'npm' + - name: Intall npm packages + if: ${{ inputs.npm == 'true' }} + shell: bash + run: npm install + + # OS installs + - name: Install OS Dependencies + if: ${{ inputs.apt-dependency }} + shell: bash + run: | + sudo apt-get update + sudo apt-get install ${{ inputs.apt-dependency }} + + # Invoke commands + - name: Run invoke install + if: ${{ inputs.install == 'true' }} + shell: bash + run: invoke install + - name: Run invoke update + if: ${{ inputs.update == 'true' }} + shell: bash + run: invoke update diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml new file mode 100644 index 0000000000..bc835efb98 --- /dev/null +++ b/.github/workflows/docker.yaml @@ -0,0 +1,69 @@ +# Build, test and push InvenTree docker image +# This workflow runs under any of the following conditions: +# +# - Push to the master branch +# - Push to the stable branch +# - Publish release +# +# The following actions are performed: +# +# - Check that the version number matches the current branch or tag +# - Build the InvenTree docker image +# - Run suite of unit tests against the build image +# - Push the compiled, tested image to dockerhub + +name: Docker + +on: + release: + types: [published] + + push: + branches: + - 'master' + - 'stable' + +jobs: + + # Build the docker image + build: + runs-on: ubuntu-latest + + steps: + - name: Check out repo + uses: actions/checkout@v2 + - name: Version Check + run: | + python3 ci/check_version_number.py + echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV + - name: Run Unit Tests + run: | + docker-compose build + docker-compose run inventree-dev-server invoke update + docker-compose up -d + docker-compose run inventree-dev-server invoke wait + docker-compose run inventree-dev-server invoke test + docker-compose down + - name: Set up QEMU + if: github.event_name != 'pull_request' + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + if: github.event_name != 'pull_request' + uses: docker/setup-buildx-action@v1 + - name: Login to Dockerhub + if: github.event_name != 'pull_request' + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Build and Push + if: github.event_name != 'pull_request' + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + target: production + tags: inventree/inventree:${{ env.docker_tag }} + build-args: commit_hash=${{ env.git_commit_hash }},commit_date=${{ env.git_commit_date }},commit_tag=${{ env.docker_tag }} diff --git a/.github/workflows/docker_latest.yaml b/.github/workflows/docker_latest.yaml deleted file mode 100644 index 74b5eb966c..0000000000 --- a/.github/workflows/docker_latest.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# Build and push latest docker image on push to master branch - -name: Docker Build - -on: - push: - branches: - - 'master' - -jobs: - - docker: - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Check version number - run: | - python3 ci/check_version_number.py --dev - - name: Build Docker Image - run: | - cd docker - docker-compose build - docker-compose run inventree-dev-server invoke update - - name: Run unit tests - run: | - cd docker - docker-compose up -d - docker-compose run inventree-dev-server invoke wait - docker-compose run inventree-dev-server invoke test - docker-compose down - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Login to Dockerhub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push - uses: docker/build-push-action@v2 - with: - context: ./docker - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: true - target: production - tags: inventree/inventree:latest - - name: Image Digest - run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/docker_stable.yaml b/.github/workflows/docker_stable.yaml deleted file mode 100644 index e892b24d13..0000000000 --- a/.github/workflows/docker_stable.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Build and push docker image on push to 'stable' branch -# Docker build will be uploaded to dockerhub with the 'inventree:stable' tag - -name: Docker Build - -on: - push: - branches: - - 'stable' - -jobs: - - docker: - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Check version number - run: | - python3 ci/check_version_number.py --release - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Login to Dockerhub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push - uses: docker/build-push-action@v2 - with: - context: ./docker - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: true - target: production - build-args: - branch=stable - tags: inventree/inventree:stable - - name: Image Digest - run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/docker_tag.yaml b/.github/workflows/docker_tag.yaml deleted file mode 100644 index a9f1c646fc..0000000000 --- a/.github/workflows/docker_tag.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Publish docker images to dockerhub on a tagged release -# Docker build will be uploaded to dockerhub with the 'invetree:' tag - -name: Docker Publish - -on: - release: - types: [published] - -jobs: - publish_image: - name: Push InvenTree web server image to dockerhub - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@v2 - - name: Check Release tag - run: | - python3 ci/check_version_number.py --release --tag ${{ github.event.release.tag_name }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Login to Dockerhub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push - uses: docker/build-push-action@v2 - with: - context: ./docker - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: true - target: production - build-args: - tag=${{ github.event.release.tag_name }} - tags: inventree/inventree:${{ github.event.release.tag_name }} diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 2245a5242f..9bc0484fa0 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -14,120 +14,97 @@ on: env: python_version: 3.9 node_version: 16 + # The OS version must be set per job server_start_sleep: 60 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} INVENTREE_DB_ENGINE: sqlite3 INVENTREE_DB_NAME: inventree - INVENTREE_MEDIA_ROOT: ./media - INVENTREE_STATIC_ROOT: ./static - + INVENTREE_MEDIA_ROOT: ../test_inventree_media + INVENTREE_STATIC_ROOT: ../test_inventree_static jobs: pep_style: - name: PEP style (python) - runs-on: ubuntu-latest + name: Style [Python] + runs-on: ubuntu-20.04 steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Set up Python ${{ env.python_version }} - uses: actions/setup-python@v2 + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup with: - python-version: ${{ env.python_version }} - cache: 'pip' - - name: Install deps - run: | - pip install flake8==3.8.3 - pip install pep8-naming==0.11.1 - - name: flake8 - run: | - flake8 InvenTree + install: true + - name: Run flake8 + run: flake8 InvenTree --extend-ignore=D javascript: - name: javascript template files + name: Style [JS] + runs-on: ubuntu-20.04 + needs: pep_style - runs-on: ubuntu-latest steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Install node.js ${{ env.node_version }} - uses: actions/setup-node@v2 + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup with: - node-version: ${{ env.node_version }} - cache: 'npm' - - run: npm install - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: ${{ env.python_version }} - cache: 'pip' - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install gettext - pip3 install invoke - invoke install - invoke static - - name: Check Templated Files + npm: true + install: true + - name: Check Templated JS Files run: | cd ci - python check_js_templates.py + python3 check_js_templates.py - name: Lint Javascript Files run: | invoke render-js-files npx eslint js_tmp/*.js html: - name: html template files + name: Style [HTML] + runs-on: ubuntu-20.04 + needs: pep_style - runs-on: ubuntu-latest steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Install node.js ${{ env.node_version }} - uses: actions/setup-node@v2 + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup with: - node-version: ${{ env.node_version }} - cache: 'npm' - - run: npm install - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: ${{ env.python_version }} - cache: 'pip' - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install gettext - pip3 install invoke - invoke install - invoke static + npm: true + install: true - name: Check HTML Files - run: | - npx markuplint InvenTree/build/templates/build/*.html - npx markuplint InvenTree/company/templates/company/*.html - npx markuplint InvenTree/order/templates/order/*.html - npx markuplint InvenTree/part/templates/part/*.html - npx markuplint InvenTree/stock/templates/stock/*.html - npx markuplint InvenTree/templates/*.html - npx markuplint InvenTree/templates/InvenTree/*.html - npx markuplint InvenTree/templates/InvenTree/settings/*.html + run: npx markuplint **/templates/*.html + + pre-commit: + name: Style [pre-commit] + runs-on: ubuntu-20.04 + + needs: pep_style + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ env.python_version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ env.python_version }} + cache: 'pip' + - name: Run pre-commit Checks + uses: pre-commit/action@v2.0.3 + - name: Check version number + run: | + python3 ci/check_version_number.py python: - name: python bindings - needs: pep_style - runs-on: ubuntu-latest + name: Tests - inventree-python + runs-on: ubuntu-20.04 + + needs: pre-commit env: wrapper_name: inventree-python INVENTREE_DB_ENGINE: django.db.backends.sqlite3 INVENTREE_DB_NAME: ../inventree_unit_test_db.sqlite3 - INVENTREE_MEDIA_ROOT: ../test_inventree_media - INVENTREE_STATIC_ROOT: ../test_inventree_static INVENTREE_ADMIN_USER: testuser INVENTREE_ADMIN_PASSWORD: testpassword INVENTREE_ADMIN_EMAIL: test@test.com @@ -136,34 +113,32 @@ jobs: INVENTREE_PYTHON_TEST_PASSWORD: testpassword steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Install InvenTree - run: | - sudo apt-get update - sudo apt-get install python3-dev python3-pip python3-venv - pip3 install invoke - invoke install - invoke migrate - - name: Download Python Code - run: | - git clone --depth 1 https://github.com/inventree/${{ env.wrapper_name }} ./${{ env.wrapper_name }} - - name: Start Server + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup + with: + apt-dependency: gettext poppler-utils + update: true + - name: Download Python Code For `${{ env.wrapper_name }}` + run: git clone --depth 1 https://github.com/inventree/${{ env.wrapper_name }} ./${{ env.wrapper_name }} + - name: Start InvenTree Server run: | invoke delete-data -f invoke import-fixtures invoke server -a 127.0.0.1:12345 & invoke wait - - name: Run Tests + - name: Run Tests For `${{ env.wrapper_name }}` run: | cd ${{ env.wrapper_name }} invoke check-server coverage run -m unittest discover -s test/ coverage: - name: Sqlite / coverage - needs: ['javascript', 'html'] - runs-on: ubuntu-latest + name: Tests - DB [SQLite] + Coverage + runs-on: ubuntu-20.04 + + needs: ['javascript', 'html', 'pre-commit'] + continue-on-error: true # continue if a step fails so that coverage gets pushed env: INVENTREE_DB_NAME: ./inventree.sqlite @@ -171,32 +146,16 @@ jobs: INVENTREE_PLUGINS_ENABLED: true steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Setup Python ${{ env.python_version }} - uses: actions/setup-python@v2 + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup with: - python-version: ${{ env.python_version }} - cache: 'pip' - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install gettext - python -m pip install -U pip - pip3 install invoke - invoke update + apt-dependency: gettext poppler-utils + update: true - name: Coverage Tests - run: | - invoke coverage - - name: Data Import Export - run: | - invoke migrate - invoke import-fixtures - invoke export-records -f data.json - rm inventree.sqlite - invoke migrate - invoke import-records -f data.json - invoke import-records -f data.json + run: invoke coverage + - name: Data Export Test + uses: ./.github/actions/migration - name: Test Translations run: invoke translate - name: Check Migration Files @@ -205,9 +164,10 @@ jobs: run: coveralls postgres: - name: Postgres - needs: ['javascript', 'html'] - runs-on: ubuntu-latest + name: Tests - DB [PostgreSQL] + runs-on: ubuntu-20.04 + + needs: ['javascript', 'html', 'pre-commit'] if: github.event_name == 'push' env: @@ -235,38 +195,23 @@ jobs: - 6379:6379 steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Setup Python ${{ env.python_version }} - uses: actions/setup-python@v2 + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup with: - python-version: ${{ env.python_version }} - cache: 'pip' - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install libpq-dev gettext - python -m pip install -U pip - pip3 install invoke - pip3 install psycopg2 - pip3 install django-redis>=5.0.0 - invoke update + apt-dependency: gettext poppler-utils libpq-dev + pip-dependency: psycopg2 django-redis>=5.0.0 + update: true - name: Run Tests run: invoke test - - name: Data Import Export - run: | - invoke migrate - python3 ./InvenTree/manage.py flush --noinput - invoke import-fixtures - invoke export-records -f data.json - python3 ./InvenTree/manage.py flush --noinput - invoke import-records -f data.json - invoke import-records -f data.json + - name: Data Export Test + uses: ./.github/actions/migration mysql: - name: MySql - needs: ['javascript', 'html'] - runs-on: ubuntu-latest + name: Tests - DB [MySQL] + runs-on: ubuntu-20.04 + + needs: ['javascript', 'html', 'pre-commit'] if: github.event_name == 'push' env: @@ -293,29 +238,14 @@ jobs: - 3306:3306 steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Setup Python ${{ env.python_version }} - uses: actions/setup-python@v2 + - uses: actions/checkout@v1 + - name: Enviroment Setup + uses: ./.github/actions/setup with: - python-version: ${{ env.python_version }} - cache: 'pip' - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install libmysqlclient-dev gettext - python -m pip install -U pip - pip3 install invoke - pip3 install mysqlclient - invoke update + apt-dependency: gettext poppler-utils libmysqlclient-dev + pip-dependency: mysqlclient + update: true - name: Run Tests run: invoke test - - name: Data Import Export - run: | - invoke migrate - python3 ./InvenTree/manage.py flush --noinput - invoke import-fixtures - invoke export-records -f data.json - python3 ./InvenTree/manage.py flush --noinput - invoke import-records -f data.json - invoke import-records -f data.json + - name: Data Export Test + uses: ./.github/actions/migration diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml deleted file mode 100644 index 73d5bd8a2c..0000000000 --- a/.github/workflows/version.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Checks version number -name: version number - -on: - pull_request: - branches-ignore: - - l10* - - -jobs: - - check_version: - name: version number - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v2 - - name: Check version number - run: | - python3 ci/check_version_number.py --branch ${{ github.base_ref }} diff --git a/.gitignore b/.gitignore index 56d4180482..9c9a45d136 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ __pycache__/ env/ inventree-env/ ./build/ +.cache/ develop-eggs/ dist/ bin/ @@ -26,7 +27,6 @@ var/ .installed.cfg *.egg - # Django stuff: *.log local_settings.py @@ -38,6 +38,8 @@ local_settings.py # Files used for testing dummy_image.* _tmp.csv +inventree/label.pdf +inventree/label.png # Sphinx files docs/_build @@ -63,6 +65,7 @@ secret_key.txt .idea/ *.code-workspace .vscode/ +.bash_history # Coverage reports .coverage diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1dc2ba3f70..269ddddee9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,10 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks +exclude: | + (?x)^( + InvenTree/InvenTree/static/.*| + InvenTree/locale/.* + )$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.2.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f1bdc6ad85..0c82d5f51d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Please read the contribution guidelines below, before submitting your first pull ## Setup -Please run `invoke setup_dev` in the root directory of your InvenTree code base to set up your development setup before starting to contribute. This will install and set up pre-commit to run some checks before each commit and help reduce the style errors. +Please run `invoke setup-dev` in the root directory of your InvenTree code base to set up your development setup before starting to contribute. This will install and set up pre-commit to run some checks before each commit and help reduce the style errors. ## Branches and Versioning diff --git a/docker/Dockerfile b/Dockerfile similarity index 53% rename from docker/Dockerfile rename to Dockerfile index 1b7c16db30..cec2424621 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -1,37 +1,39 @@ -FROM alpine:3.14 as base +# The InvenTree dockerfile provides two build targets: +# +# production: +# - Required files are copied into the image +# - Runs InvenTree web server under gunicorn +# +# dev: +# - Expects source directories to be loaded as a run-time volume +# - Runs InvenTree web server under django development server +# - Monitors source files for any changes, and live-reloads server -# GitHub source -ARG repository="https://github.com/inventree/InvenTree.git" -ARG branch="master" -# Optionally specify a particular tag to checkout -ARG tag="" +FROM python:3.9-slim as base + +# Build arguments for this image +ARG commit_hash="" +ARG commit_date="" +ARG commit_tag="" ENV PYTHONUNBUFFERED 1 # Ref: https://github.com/pyca/cryptography/issues/5776 ENV CRYPTOGRAPHY_DONT_BUILD_RUST 1 -# InvenTree key settings - -# The INVENTREE_HOME directory is where the InvenTree source repository will be located -ENV INVENTREE_HOME="/home/inventree" - -# GitHub settings -ENV INVENTREE_GIT_REPO="${repository}" -ENV INVENTREE_GIT_BRANCH="${branch}" -ENV INVENTREE_GIT_TAG="${tag}" - ENV INVENTREE_LOG_LEVEL="INFO" ENV INVENTREE_DOCKER="true" # InvenTree paths +ENV INVENTREE_HOME="/home/inventree" ENV INVENTREE_MNG_DIR="${INVENTREE_HOME}/InvenTree" ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/data" ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static" ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media" ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DATA_DIR}/plugins" +# InvenTree configuration files ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml" ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt" ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DATA_DIR}/plugins.txt" @@ -49,82 +51,83 @@ LABEL org.label-schema.schema-version="1.0" \ org.label-schema.vendor="inventree" \ org.label-schema.name="inventree/inventree" \ org.label-schema.url="https://hub.docker.com/r/inventree/inventree" \ - org.label-schema.vcs-url=${INVENTREE_GIT_REPO} \ - org.label-schema.vcs-branch=${INVENTREE_GIT_BRANCH} \ - org.label-schema.vcs-ref=${INVENTREE_GIT_TAG} + org.label-schema.vcs-url="https://github.com/inventree/InvenTree.git" \ + org.label-schema.vcs-ref=${commit_tag} -# Create user account -RUN addgroup -S inventreegroup && adduser -S inventree -G inventreegroup - -RUN apk -U upgrade +# RUN apt-get upgrade && apt-get update +RUN apt-get update # Install required system packages -RUN apk add --no-cache git make bash \ - gcc libgcc g++ libstdc++ \ - gnupg \ - libjpeg-turbo libjpeg-turbo-dev jpeg jpeg-dev libwebp-dev \ - libffi libffi-dev \ - zlib zlib-dev \ - # Special deps for WeasyPrint (these will be deprecated once WeasyPrint drops cairo requirement) - cairo cairo-dev pango pango-dev gdk-pixbuf \ - # Fonts - fontconfig ttf-droid ttf-liberation ttf-dejavu ttf-opensans font-croscore font-noto \ - # Core python - python3 python3-dev py3-pip \ +RUN apt-get install -y --no-install-recommends \ + git gcc g++ gettext gnupg libffi-dev \ + # Weasyprint requirements : https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#debian-11 + poppler-utils libpango-1.0-0 libpangoft2-1.0-0 \ + # Image format support + libjpeg-dev webp \ # SQLite support - sqlite \ + sqlite3 \ # PostgreSQL support - postgresql postgresql-contrib postgresql-dev libpq \ - # MySQL/MariaDB support - mariadb-connector-c mariadb-dev mariadb-client \ - # Required for python cryptography support - openssl-dev musl-dev libffi-dev rust cargo + libpq-dev \ + # MySQL / MariaDB support + default-libmysqlclient-dev mariadb-client && \ + apt-get autoclean && apt-get autoremove # Update pip RUN pip install --upgrade pip # Install required base-level python packages -COPY requirements.txt requirements.txt -RUN pip install --no-cache-dir -U -r requirements.txt +COPY ./docker/requirements.txt base_requirements.txt +RUN pip install --disable-pip-version-check -U -r base_requirements.txt + +# InvenTree production image: +# - Copies required files from local directory +# - Installs required python packages from requirements.txt +# - Starts a gunicorn webserver -# Production code (pulled from tagged github release) FROM base as production -# Clone source code -RUN echo "Downloading InvenTree from ${INVENTREE_GIT_REPO}" +ENV INVENTREE_DEBUG=False -RUN git clone --branch ${INVENTREE_GIT_BRANCH} --depth 1 ${INVENTREE_GIT_REPO} ${INVENTREE_HOME} +# As .git directory is not available in production image, we pass the commit information via ENV +ENV INVENTREE_COMMIT_HASH="${commit_hash}" +ENV INVENTREE_COMMIT_DATE="${commit_date}" -# Ref: https://github.blog/2022-04-12-git-security-vulnerability-announced/ -RUN git config --global --add safe.directory ${INVENTREE_HOME} +# Copy source code +COPY InvenTree ${INVENTREE_HOME}/InvenTree -# Checkout against a particular git tag -RUN if [ -n "${INVENTREE_GIT_TAG}" ] ; then cd ${INVENTREE_HOME} && git fetch --all --tags && git checkout tags/${INVENTREE_GIT_TAG} -b v${INVENTREE_GIT_TAG}-branch ; fi - -RUN chown -R inventree:inventreegroup ${INVENTREE_HOME}/* - -# Drop to the inventree user -USER inventree - -# Install InvenTree packages -RUN pip3 install --user --no-cache-dir --disable-pip-version-check -r ${INVENTREE_HOME}/requirements.txt +# Copy other key files +COPY requirements.txt ${INVENTREE_HOME}/requirements.txt +COPY tasks.py ${INVENTREE_HOME}/tasks.py +COPY docker/gunicorn.conf.py ${INVENTREE_HOME}/gunicorn.conf.py +COPY docker/init.sh ${INVENTREE_MNG_DIR}/init.sh # Need to be running from within this directory WORKDIR ${INVENTREE_MNG_DIR} +# Drop to the inventree user for the production image +RUN adduser inventree +RUN chown -R inventree:inventree ${INVENTREE_HOME} + +USER inventree + +# Install InvenTree packages +RUN pip3 install --user --disable-pip-version-check -r ${INVENTREE_HOME}/requirements.txt + # Server init entrypoint -ENTRYPOINT ["/bin/bash", "../docker/init.sh"] +ENTRYPOINT ["/bin/bash", "./init.sh"] # Launch the production server # TODO: Work out why environment variables cannot be interpolated in this command # TODO: e.g. -b ${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT} fails here -CMD gunicorn -c ./docker/gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ./InvenTree +CMD gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ./InvenTree FROM base as dev # The development image requires the source code to be mounted to /home/inventree/ # So from here, we don't actually "do" anything, apart from some file management +ENV INVENTREE_DEBUG=True + ENV INVENTREE_DEV_DIR="${INVENTREE_HOME}/dev" # Location for python virtual environment diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index 935252de5b..5385f8f01b 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -117,6 +117,11 @@ class InvenTreeAPITestCase(UserMixin, APITestCase): response = self.client.get(url, data, format='json') if expected_code is not None: + + if response.status_code != expected_code: + print(f"Unexpected response at '{url}':") + print(response.data) + self.assertEqual(response.status_code, expected_code) return response diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index e44aedf10b..993c7e9980 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -4,11 +4,14 @@ InvenTree API version information # InvenTree API version -INVENTREE_API_VERSION = 50 +INVENTREE_API_VERSION = 51 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v51 -> 2022-05-24 : https://github.com/inventree/InvenTree/pull/3058 + - Adds new fields to the SalesOrderShipment model + v50 -> 2022-05-18 : https://github.com/inventree/InvenTree/pull/2912 - Implement Attachments for manufacturer parts diff --git a/InvenTree/InvenTree/exceptions.py b/InvenTree/InvenTree/exceptions.py index 55017affc0..a4737bac4d 100644 --- a/InvenTree/InvenTree/exceptions.py +++ b/InvenTree/InvenTree/exceptions.py @@ -40,7 +40,11 @@ def exception_handler(exc, context): if response is None: # DRF handler did not provide a default response for this exception - if settings.DEBUG: + if settings.TESTING: + # If in TESTING mode, re-throw the exception for traceback + raise exc + elif settings.DEBUG: + # If in DEBUG mode, provide error information in the response error_detail = str(exc) else: error_detail = _("Error details can be found in the admin panel") diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index c541ce4ef5..00ac33ae68 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -129,7 +129,7 @@ def TestIfImageURL(url): Simply tests the extension against a set of allowed values """ return os.path.splitext(os.path.basename(url))[-1].lower() in [ - '.jpg', '.jpeg', + '.jpg', '.jpeg', '.j2k', '.png', '.bmp', '.tif', '.tiff', '.webp', '.gif', diff --git a/InvenTree/InvenTree/status_codes.py b/InvenTree/InvenTree/status_codes.py index 57bacc861e..15f3d872bb 100644 --- a/InvenTree/InvenTree/status_codes.py +++ b/InvenTree/InvenTree/status_codes.py @@ -173,12 +173,9 @@ class StockStatus(StatusCode): DESTROYED = 60 # Item is destroyed REJECTED = 65 # Item is rejected LOST = 70 # Item has been lost + QUARANTINED = 75 # Item has been quarantined and is unavailable RETURNED = 85 # Item has been returned from a customer - # Any stock code above 100 means that the stock item is not "in stock" - # This can be used as a quick check for filtering - NOT_IN_STOCK = 100 - options = { OK: _("OK"), ATTENTION: _("Attention needed"), @@ -186,6 +183,7 @@ class StockStatus(StatusCode): DESTROYED: _("Destroyed"), LOST: _("Lost"), REJECTED: _("Rejected"), + QUARANTINED: _("Quarantined"), RETURNED: _("Returned"), } @@ -196,6 +194,7 @@ class StockStatus(StatusCode): DESTROYED: 'danger', LOST: 'dark', REJECTED: 'danger', + QUARANTINED: 'info' } # The following codes correspond to parts that are 'available' or 'in stock' @@ -206,22 +205,6 @@ class StockStatus(StatusCode): RETURNED, ] - # The following codes correspond to parts that are 'unavailable' - UNAVAILABLE_CODES = [ - DESTROYED, - LOST, - REJECTED, - ] - - # The following codes are available for receiving goods - RECEIVING_CODES = [ - OK, - ATTENTION, - DAMAGED, - DESTROYED, - REJECTED - ] - class StockHistoryCode(StatusCode): diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index f306cce32a..3de293ca66 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -380,6 +380,30 @@ class TestVersionNumber(TestCase): self.assertTrue(v_d > v_c) self.assertTrue(v_d > v_a) + def test_commit_info(self): + """Test that the git commit information is extracted successfully""" + + envs = { + 'INVENTREE_COMMIT_HASH': 'abcdef', + 'INVENTREE_COMMIT_DATE': '2022-12-31' + } + + # Check that the environment variables take priority + + with mock.patch.dict(os.environ, envs): + self.assertEqual(version.inventreeCommitHash(), 'abcdef') + self.assertEqual(version.inventreeCommitDate(), '2022-12-31') + + import subprocess + + # Check that the current .git values work too + + hash = str(subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8').strip() + self.assertEqual(hash, version.inventreeCommitHash()) + + d = str(subprocess.check_output('git show -s --format=%ci'.split()), 'utf-8').strip().split(' ')[0] + self.assertEqual(d, version.inventreeCommitDate()) + class CurrencyTests(TestCase): """ @@ -522,7 +546,7 @@ class TestSettings(helpers.InvenTreeTestCase): # Set dynamic setting to True and rerun to launch install InvenTreeSetting.set_setting('PLUGIN_ON_STARTUP', True, self.user) - registry.reload_plugins() + registry.reload_plugins(full_reload=True) # Check that there was anotehr run response = registry.install_plugin_file() diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 7d9cbad102..fe970ee5d4 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -3,6 +3,7 @@ Version information for InvenTree. Provides information on the current InvenTree version """ +import os import re import subprocess @@ -12,7 +13,7 @@ import common.models from InvenTree.api_version import INVENTREE_API_VERSION # InvenTree software version -INVENTREE_SW_VERSION = "0.7.0 dev" +INVENTREE_SW_VERSION = "0.8.0 dev" def inventreeInstanceName(): @@ -99,6 +100,12 @@ def inventreeDjangoVersion(): def inventreeCommitHash(): """ Returns the git commit hash for the running codebase """ + # First look in the environment variables, i.e. if running in docker + commit_hash = os.environ.get('INVENTREE_COMMIT_HASH', '') + + if commit_hash: + return commit_hash + try: return str(subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8').strip() except: # pragma: no cover @@ -108,6 +115,12 @@ def inventreeCommitHash(): def inventreeCommitDate(): """ Returns the git commit date for the running codebase """ + # First look in the environment variables, e.g. if running in docker + commit_date = os.environ.get('INVENTREE_COMMIT_DATE', '') + + if commit_date: + return commit_date.split(' ')[0] + try: d = str(subprocess.check_output('git show -s --format=%ci'.split()), 'utf-8').strip() return d.split(' ')[0] diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index dca3fe359d..f99a7efb95 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -355,8 +355,9 @@ onPanelLoad('completed', function() { onPanelLoad('children', function() { loadBuildTable($('#sub-build-table'), { - url: '{% url "api-build-list" %}', + locale: '{{ request.LANGUAGE_CODE }}', filterTarget: "#filter-list-sub-build", + parentBuild: {{ build.pk }}, params: { ancestor: {{ build.pk }}, } @@ -527,11 +528,7 @@ $('#btn-unallocate').on('click', function() { $('#allocate-selected-items').click(function() { - var bom_items = $("#allocation-table-untracked").bootstrapTable("getSelections"); - - if (bom_items.length == 0) { - bom_items = $("#allocation-table-untracked").bootstrapTable('getData'); - } + var bom_items = getTableData('#allocation-table-untracked'); allocateStockToBuild( {{ build.pk }}, diff --git a/InvenTree/build/templates/build/index.html b/InvenTree/build/templates/build/index.html index 4dbf2aba7a..4d1476f959 100644 --- a/InvenTree/build/templates/build/index.html +++ b/InvenTree/build/templates/build/index.html @@ -40,13 +40,6 @@ {% endif %} - - - {% include "filter_list.html" with id="build" %} @@ -54,139 +47,24 @@
- -
{% endblock %} -{% block js_load %} -{{ block.super }} - - -{% endblock %} - {% block js_ready %} {{ block.super }} -$('#build-order-calendar').hide(); -$('#view-list').hide(); - -$('#view-calendar').click(function() { - // Hide the list view, show the calendar view - $("#build-table").hide(); - $("#view-calendar").hide(); - $(".fixed-table-pagination").hide(); - $(".columns-right").hide(); - $(".search").hide(); - - $("#build-order-calendar").show(); - $("#view-list").show(); - - calendar.render(); -}); - -$("#view-list").click(function() { - // Hide the calendar view, show the list view - $("#build-order-calendar").hide(); - $("#view-list").hide(); - - $(".fixed-table-pagination").show(); - $(".columns-right").show(); - $(".search").show(); - $("#build-table").show(); - $("#view-calendar").show(); -}); - -$("#collapse-item-active").collapse().show(); - $("#new-build").click(function() { newBuildOrder(); }); loadBuildTable($("#build-table"), { - url: "{% url 'api-build-list' %}", + locale: '{{ request.LANGUAGE_CODE }}', }); {% if report_enabled %} $('#multi-build-print').click(function() { - var rows = $("#build-table").bootstrapTable('getSelections'); - + var rows = getTableData("#build-table"); var build_ids = []; rows.forEach(function(row) { diff --git a/InvenTree/common/notifications.py b/InvenTree/common/notifications.py index c2e4f2d6aa..aa39ad20ef 100644 --- a/InvenTree/common/notifications.py +++ b/InvenTree/common/notifications.py @@ -203,7 +203,7 @@ class UIMessageNotification(SingleNotificationMethod): return True -def trigger_notifaction(obj, category=None, obj_ref='pk', **kwargs): +def trigger_notification(obj, category=None, obj_ref='pk', **kwargs): """ Send out a notification """ diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 9ae40f0833..a5e2e159fc 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -28,8 +28,8 @@
-