Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4d9aa9d1b | ||
|
|
54f2072e97 | ||
|
|
d1042cde0e | ||
|
|
5f4275679d | ||
|
|
1ba0bee1ea | ||
|
|
ea7aa93a28 | ||
|
|
9eccf69456 | ||
|
|
9cebfa85df | ||
|
|
af3cf62b8e | ||
|
|
f20a1245e7 | ||
|
|
92a4989a8d | ||
|
|
be3b22ce36 | ||
|
|
258b8e4ecc | ||
|
|
7df92aad03 | ||
|
|
2dac705779 |
@@ -1,43 +0,0 @@
|
||||
# Dockerfile for the InvenTree devcontainer
|
||||
|
||||
# In contrast with the "production" image (which is based on an Alpine image)
|
||||
# we use a Debian-based image for the devcontainer
|
||||
|
||||
FROM mcr.microsoft.com/devcontainers/python:3.11-bookworm@sha256:5140e54af7a0399a4932dd4c4653d085fcf451b093d7424867df1828ffbb9b81
|
||||
|
||||
# InvenTree paths
|
||||
ENV INVENTREE_HOME="/home/inventree"
|
||||
ENV INVENTREE_DATA_DIR="${INVENTREE_HOME}/dev"
|
||||
ENV INVENTREE_STATIC_ROOT="${INVENTREE_DATA_DIR}/static"
|
||||
ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media"
|
||||
ENV INVENTREE_BACKUP_DIR="${INVENTREE_DATA_DIR}/backup"
|
||||
ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DATA_DIR}/plugins"
|
||||
ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml"
|
||||
ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt"
|
||||
ENV INVENTREE_OIDC_PRIVATE_KEY_FILE="${INVENTREE_DATA_DIR}/oidc.pem"
|
||||
|
||||
# Required for running playwright within devcontainer
|
||||
ENV DISPLAY=:0
|
||||
ENV LIBGL_ALWAYS_INDIRECT=1
|
||||
|
||||
COPY contrib/container/init.sh ./
|
||||
RUN chmod +x init.sh
|
||||
|
||||
# Install required base packages
|
||||
RUN apt update && apt install -y \
|
||||
python3.11-dev python3.11-venv \
|
||||
postgresql-client \
|
||||
libldap2-dev libsasl2-dev \
|
||||
libpango1.0-0 libcairo2 \
|
||||
poppler-utils weasyprint
|
||||
|
||||
# Install packages required for frontend development
|
||||
RUN apt install -y \
|
||||
yarn nodejs npm
|
||||
|
||||
# Update to the latest stable node version
|
||||
RUN npm install -g n --ignore-scripts && n lts
|
||||
|
||||
RUN yarn config set network-timeout 600000 -g
|
||||
|
||||
ENTRYPOINT ["/bin/bash", "./init.sh"]
|
||||
@@ -31,24 +31,17 @@
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"batisteo.vscode-django",
|
||||
"eamodio.gitlens",
|
||||
"biomejs.biome"
|
||||
"eamodio.gitlens"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [5173, 5432, 6379, 8000, 8080],
|
||||
"forwardPorts": [5173, 8000, 8080],
|
||||
"portsAttributes": {
|
||||
"5173": {
|
||||
"label": "Vite Server"
|
||||
},
|
||||
"5432": {
|
||||
"label": "PostgreSQL Database"
|
||||
},
|
||||
"6379": {
|
||||
"label": "Redis Server"
|
||||
},
|
||||
"8000": {
|
||||
"label": "InvenTree Server"
|
||||
},
|
||||
|
||||
@@ -1,46 +1,43 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:15
|
||||
image: postgres:13
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
expose:
|
||||
- 5432/tcp
|
||||
volumes:
|
||||
- ../dev-db/:/var/lib/postgresql/data:z
|
||||
- inventreedatabase:/var/lib/postgresql/data:z
|
||||
environment:
|
||||
POSTGRES_DB: inventree
|
||||
POSTGRES_USER: inventree_user
|
||||
POSTGRES_PASSWORD: inventree_password
|
||||
|
||||
redis:
|
||||
image: redis:7.0
|
||||
restart: always
|
||||
ports:
|
||||
- 6379
|
||||
|
||||
inventree:
|
||||
ports:
|
||||
- 8000:8000
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: .devcontainer/Dockerfile
|
||||
dockerfile: ../InvenTree/contrib/container/Dockerfile
|
||||
target: dev
|
||||
args:
|
||||
base_image: "mcr.microsoft.com/vscode/devcontainers/base:alpine-3.18"
|
||||
data_dir: "dev"
|
||||
volumes:
|
||||
- ../:/home/inventree:z
|
||||
- /tmp/.X11-unix:/tmp/.X11-unix
|
||||
|
||||
environment:
|
||||
INVENTREE_DEBUG: True
|
||||
INVENTREE_DB_ENGINE: postgresql
|
||||
INVENTREE_DB_NAME: inventree
|
||||
INVENTREE_DB_HOST: db
|
||||
INVENTREE_DB_USER: inventree_user
|
||||
INVENTREE_DB_PASSWORD: inventree_password
|
||||
INVENTREE_DEBUG: True
|
||||
INVENTREE_CACHE_HOST: redis
|
||||
INVENTREE_CACHE_PORT: 6379
|
||||
INVENTREE_PLUGINS_ENABLED: True
|
||||
INVENTREE_SITE_URL: http://localhost:8000
|
||||
INVENTREE_CORS_ORIGIN_ALLOW_ALL: True
|
||||
INVENTREE_PY_ENV: /home/inventree/dev/venv
|
||||
INVENTREE_DEVCONTAINER: True
|
||||
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
volumes:
|
||||
inventreedatabase:
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Running postCreateCommand.sh ..."
|
||||
|
||||
# Avoiding Dubious Ownership in Dev Containers for setup commands that use git
|
||||
git config --global --add safe.directory /home/inventree
|
||||
@@ -10,30 +7,16 @@ git config --global --add safe.directory /home/inventree
|
||||
python3 -m venv /home/inventree/dev/venv --system-site-packages --upgrade-deps
|
||||
. /home/inventree/dev/venv/bin/activate
|
||||
|
||||
# remove existing gitconfig created by "Avoiding Dubious Ownership" step
|
||||
# so that it gets copied from host to the container to have your global
|
||||
# git config in container
|
||||
rm -f /home/vscode/.gitconfig
|
||||
|
||||
# Fix issue related to CFFI version mismatch
|
||||
pip uninstall cffi -y
|
||||
sudo apt remove --purge -y python3-cffi
|
||||
pip install --no-cache-dir --force-reinstall --ignore-installed cffi
|
||||
|
||||
# Upgrade pip
|
||||
python3 -m pip install --upgrade pip
|
||||
|
||||
# Ensure the correct invoke is available
|
||||
pip3 install --ignore-installed --upgrade invoke Pillow
|
||||
|
||||
# install base level packages
|
||||
pip3 install -Ur contrib/container/requirements.txt --require-hashes
|
||||
|
||||
# Run initial InvenTree server setup
|
||||
invoke update -s
|
||||
|
||||
# Configure dev environment
|
||||
invoke dev.setup-dev
|
||||
invoke setup-dev
|
||||
|
||||
# Install required frontend packages
|
||||
invoke int.frontend-install
|
||||
invoke frontend-install
|
||||
|
||||
# remove existing gitconfig created by "Avoiding Dubious Ownership" step
|
||||
# so that it gets copied from host to the container to have your global
|
||||
# git config in container
|
||||
rm -f /home/vscode/.gitconfig
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- stable
|
||||
- refs/tags/*
|
||||
paths:
|
||||
include:
|
||||
- src/backend
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
Python39:
|
||||
PYTHON_VERSION: '3.9'
|
||||
maxParallel: 3
|
||||
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '$(PYTHON_VERSION)'
|
||||
architecture: 'x64'
|
||||
|
||||
- task: PythonScript@0
|
||||
displayName: 'Export project path'
|
||||
inputs:
|
||||
scriptSource: 'inline'
|
||||
script: |
|
||||
"""Search all subdirectories for `manage.py`."""
|
||||
from glob import iglob
|
||||
from os import path
|
||||
# Python >= 3.5
|
||||
manage_py = next(iglob(path.join('**', 'manage.py'), recursive=True), None)
|
||||
if not manage_py:
|
||||
raise SystemExit('Could not find a Django project')
|
||||
project_location = path.dirname(path.abspath(manage_py))
|
||||
print('Found Django project in', project_location)
|
||||
print('##vso[task.setvariable variable=projectRoot]{}'.format(project_location))
|
||||
|
||||
- script: |
|
||||
python -m pip install --upgrade pip setuptools wheel uv
|
||||
uv pip install --require-hashes -r src/backend/requirements.txt
|
||||
uv pip install --require-hashes -r src/backend/requirements-dev.txt
|
||||
sudo apt-get install poppler-utils
|
||||
sudo apt-get install libpoppler-dev
|
||||
uv pip install unittest-xml-reporting coverage invoke
|
||||
displayName: 'Install prerequisites'
|
||||
env:
|
||||
UV_SYSTEM_PYTHON: 1
|
||||
|
||||
- script: |
|
||||
pushd '$(projectRoot)'
|
||||
invoke update --uv
|
||||
coverage run manage.py test --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner --no-input
|
||||
coverage xml -i
|
||||
displayName: 'Run tests'
|
||||
env:
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_DB_NAME: inventree
|
||||
INVENTREE_MEDIA_ROOT: ./media
|
||||
INVENTREE_STATIC_ROOT: ./static
|
||||
INVENTREE_BACKUP_DIR: ./backup
|
||||
INVENTREE_SITE_URL: http://localhost:8000
|
||||
INVENTREE_PLUGINS_ENABLED: true
|
||||
UV_SYSTEM_PYTHON: 1
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: INFO
|
||||
|
||||
- task: PublishTestResults@2
|
||||
inputs:
|
||||
testResultsFiles: "**/TEST-*.xml"
|
||||
testRunTitle: 'Python $(PYTHON_VERSION)'
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishCodeCoverageResults@2
|
||||
inputs:
|
||||
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
|
||||
71
.devops/testing_ci.yml
Normal file
@@ -0,0 +1,71 @@
|
||||
# Python Django
|
||||
# Test a Django project on multiple versions of Python.
|
||||
# Add steps that analyze code, save build artifacts, deploy, and more:
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
|
||||
|
||||
trigger:
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
Python39:
|
||||
PYTHON_VERSION: '3.9'
|
||||
maxParallel: 3
|
||||
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '$(PYTHON_VERSION)'
|
||||
architecture: 'x64'
|
||||
|
||||
- task: PythonScript@0
|
||||
displayName: 'Export project path'
|
||||
inputs:
|
||||
scriptSource: 'inline'
|
||||
script: |
|
||||
"""Search all subdirectories for `manage.py`."""
|
||||
from glob import iglob
|
||||
from os import path
|
||||
# Python >= 3.5
|
||||
manage_py = next(iglob(path.join('**', 'manage.py'), recursive=True), None)
|
||||
if not manage_py:
|
||||
raise SystemExit('Could not find a Django project')
|
||||
project_location = path.dirname(path.abspath(manage_py))
|
||||
print('Found Django project in', project_location)
|
||||
print('##vso[task.setvariable variable=projectRoot]{}'.format(project_location))
|
||||
|
||||
- script: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install --require-hashes -r requirements.txt
|
||||
pip install --require-hashes -r requirements-dev.txt
|
||||
pip install unittest-xml-reporting coverage invoke
|
||||
sudo apt-get install poppler-utils
|
||||
sudo apt-get install libpoppler-dev
|
||||
displayName: 'Install prerequisites'
|
||||
|
||||
- script: |
|
||||
pushd '$(projectRoot)'
|
||||
invoke update
|
||||
coverage run manage.py test --testrunner xmlrunner.extra.djangotestrunner.XMLTestRunner --no-input
|
||||
coverage xml -i
|
||||
displayName: 'Run tests'
|
||||
env:
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_DB_NAME: inventree
|
||||
INVENTREE_MEDIA_ROOT: ./media
|
||||
INVENTREE_STATIC_ROOT: ./static
|
||||
INVENTREE_BACKUP_DIR: ./backup
|
||||
INVENTREE_PLUGINS_ENABLED: true
|
||||
|
||||
- task: PublishTestResults@2
|
||||
inputs:
|
||||
testResultsFiles: "**/TEST-*.xml"
|
||||
testRunTitle: 'Python $(PYTHON_VERSION)'
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- task: PublishCodeCoverageResults@1
|
||||
inputs:
|
||||
codeCoverageTool: Cobertura
|
||||
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
|
||||
4
.github/FUNDING.yml
vendored
@@ -1,3 +1,5 @@
|
||||
polar: inventree
|
||||
github: inventree
|
||||
ko_fi: inventree
|
||||
patreon: inventree
|
||||
polar: inventree
|
||||
custom: [paypal.me/inventree]
|
||||
|
||||
34
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
label: "Please verify that this bug has NOT been raised before."
|
||||
description: "Search in the issues sections by clicking [HERE](https://github.com/inventree/inventree/issues?q=) and read the [Frequently Asked Questions](https://docs.inventree.org/en/latest/sref/faq)!"
|
||||
description: "Search in the issues sections by clicking [HERE](https://github.com/inventree/inventree/issues?q=) and read the [Frequently Asked Questions](https://docs.inventree.org/en/latest/faq/)!"
|
||||
options:
|
||||
- label: "I checked and didn't find a similar issue"
|
||||
required: true
|
||||
@@ -37,15 +37,15 @@ body:
|
||||
label: "Expected behaviour"
|
||||
description: "A clear and concise description of what you expected to happen."
|
||||
placeholder: "..."
|
||||
- type: dropdown
|
||||
- type: checkboxes
|
||||
id: deployment
|
||||
attributes:
|
||||
label: "Deployment Method"
|
||||
options:
|
||||
- Docker
|
||||
- Package
|
||||
- Bare metal
|
||||
- Other - added info in Steps to Reproduce
|
||||
- label: "Docker"
|
||||
- label: "Package"
|
||||
- label: "Bare metal"
|
||||
- label: "Other - added info in Steps to Reproduce"
|
||||
- type: textarea
|
||||
id: version-info
|
||||
validations:
|
||||
@@ -54,25 +54,13 @@ body:
|
||||
label: "Version Information"
|
||||
description: "The version info block."
|
||||
placeholder: "You can get this by going to the `About InvenTree` section in the upper right corner and clicking on the `copy version information` button"
|
||||
- type: dropdown
|
||||
id: tried-reproduce
|
||||
- type: checkboxes
|
||||
id: can-reproduce
|
||||
attributes:
|
||||
label: Try to reproduce on the demo site
|
||||
description: You can sign in at [InvenTree Demo](https://demo.inventree.org) with admin:inventree. Note that this instance runs on the latest dev version, so your bug may be fixed there.
|
||||
label: "Please verify if you can reproduce this bug on the demo site."
|
||||
description: "You can sign in at [InvenTree Demo](https://demo.inventree.org) with admin:inventree. Note that this instance runs on the latest dev version, so your bug may be fixed there."
|
||||
options:
|
||||
- I did not try to reproduce
|
||||
- I tried to reproduce
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: result-reproduce
|
||||
attributes:
|
||||
label: Is the bug reproducible on the demo site?
|
||||
options:
|
||||
- Not reproducible
|
||||
- Reproducible
|
||||
validations:
|
||||
required: true
|
||||
- label: "I can reproduce this bug on the demo site."
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
6
.github/actions/migration/action.yaml
vendored
@@ -9,9 +9,9 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
invoke migrate
|
||||
invoke dev.import-fixtures
|
||||
invoke import-fixtures
|
||||
invoke export-records -f data.json
|
||||
python3 ./src/backend/InvenTree/manage.py flush --noinput
|
||||
invoke migrate
|
||||
invoke import-records -c -f data.json
|
||||
invoke import-records -c -f data.json
|
||||
invoke import-records -f data.json
|
||||
invoke import-records -f data.json
|
||||
|
||||
32
.github/actions/setup/action.yaml
vendored
@@ -35,9 +35,7 @@ runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1
|
||||
|
||||
# Python installs
|
||||
- name: Set up Python ${{ env.python_version }}
|
||||
@@ -46,27 +44,20 @@ runs:
|
||||
with:
|
||||
python-version: ${{ env.python_version }}
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
src/backend/requirements.txt
|
||||
src/backend/requirements-dev.txt
|
||||
contrib/container/requirements.txt
|
||||
contrib/dev_reqs/requirements.txt
|
||||
- name: Install Base Python Dependencies
|
||||
if: ${{ inputs.python == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
python3 -m pip install -U pip
|
||||
pip3 install -U invoke wheel
|
||||
pip3 install 'uv>=0.9.6'
|
||||
pip3 install 'uv<0.3.0'
|
||||
- name: Allow uv to use the system Python by default
|
||||
run: echo "UV_SYSTEM_PYTHON=1" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Install Specific Python Dependencies
|
||||
if: ${{ inputs.pip-dependency }}
|
||||
shell: bash
|
||||
run: uv pip install ${PIP_DEPS}
|
||||
env:
|
||||
PIP_DEPS: ${{ inputs.pip-dependency }}
|
||||
run: uv pip install ${{ inputs.pip-dependency }}
|
||||
|
||||
# NPM installs
|
||||
- name: Install node.js ${{ env.node_version }}
|
||||
@@ -74,20 +65,25 @@ runs:
|
||||
uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # pin to v3.8.2
|
||||
with:
|
||||
node-version: ${{ env.node_version }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: src/backend/package-lock.json
|
||||
- name: Install npm packages
|
||||
if: ${{ inputs.npm == 'true' }}
|
||||
shell: bash
|
||||
run: cd src/backend && npm install
|
||||
|
||||
# OS installs
|
||||
- name: Install OS Dependencies
|
||||
if: ${{ inputs.apt-dependency }}
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ${APT_DEPS}
|
||||
sudo apt-get install ${APT_DEPS}
|
||||
env:
|
||||
APT_DEPS: ${{ inputs.apt-dependency }}
|
||||
sudo apt-get install ${{ inputs.apt-dependency }}
|
||||
sudo apt-get install ${{ inputs.apt-dependency }}
|
||||
|
||||
# Invoke commands
|
||||
- name: Install dev requirements
|
||||
if: ${{ inputs.dev-install == 'true' || inputs.install == 'true' }}
|
||||
if: ${{ inputs.dev-install == 'true' ||inputs.install == 'true' }}
|
||||
shell: bash
|
||||
run: uv pip install --require-hashes -r src/backend/requirements-dev.txt
|
||||
- name: Run invoke install
|
||||
@@ -97,4 +93,4 @@ runs:
|
||||
- name: Run invoke update
|
||||
if: ${{ inputs.update == 'true' }}
|
||||
shell: bash
|
||||
run: invoke update --uv --skip-backup --skip-static
|
||||
run: invoke update --uv
|
||||
|
||||
36
.github/dependabot.yml
vendored
@@ -14,31 +14,41 @@ updates:
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
- package-ecosystem: docker
|
||||
directory: /.devcontainer
|
||||
- package-ecosystem: pip
|
||||
directory: /contrib/container
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
- package-ecosystem: pip
|
||||
directories:
|
||||
- /docs
|
||||
- /contrib/dev_reqs
|
||||
- /contrib/container
|
||||
- /src/backend
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
- package-ecosystem: pip
|
||||
directory: /.github
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
- package-ecosystem: pip
|
||||
directory: /src/backend
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: friday
|
||||
groups:
|
||||
dependencies:
|
||||
patterns:
|
||||
- "*" # Include all dependencies
|
||||
assignees:
|
||||
- "matmair"
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: npm
|
||||
directories:
|
||||
- /src/frontend
|
||||
directory: /src/backend
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
dependencies:
|
||||
patterns:
|
||||
- "*" # Include all dependencies
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: /src/frontend
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
|
||||
4
.github/release.yml
vendored
@@ -4,7 +4,6 @@ changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- translation
|
||||
- translations
|
||||
- documentation
|
||||
categories:
|
||||
- title: Breaking Changes
|
||||
@@ -14,9 +13,6 @@ changelog:
|
||||
- title: Security Patches
|
||||
labels:
|
||||
- security
|
||||
- title: Database Changes
|
||||
labels:
|
||||
- migration
|
||||
- title: New Features
|
||||
labels:
|
||||
- Semver-Minor
|
||||
|
||||
103
.github/scripts/check_js_templates.py
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
"""Test that the "translated" javascript files to not contain template tags which need to be determined at "run time".
|
||||
|
||||
This is because the "translated" javascript files are compiled into the "static" directory.
|
||||
They should only contain template tags that render static information.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
template_dir = os.path.abspath(os.path.join(here, '..', 'InvenTree', 'templates'))
|
||||
|
||||
# We only care about the 'translated' files
|
||||
js_i18n_dir = os.path.join(template_dir, 'js', 'translated')
|
||||
js_dynamic_dir = os.path.join(template_dir, 'js', 'dynamic')
|
||||
|
||||
errors = 0
|
||||
|
||||
print('=================================')
|
||||
print('Checking static javascript files:')
|
||||
print('=================================')
|
||||
|
||||
|
||||
def check_invalid_tag(data):
|
||||
"""Check for invalid tags."""
|
||||
pattern = r'{%(\w+)'
|
||||
|
||||
err_count = 0
|
||||
|
||||
for idx, line in enumerate(data):
|
||||
results = re.findall(pattern, line)
|
||||
|
||||
for result in results:
|
||||
err_count += 1
|
||||
|
||||
print(f' - Error on line {idx + 1}: %{{{result[0]}')
|
||||
|
||||
return err_count
|
||||
|
||||
|
||||
def check_prohibited_tags(data):
|
||||
"""Check for prohibited tags."""
|
||||
allowed_tags = [
|
||||
'if',
|
||||
'elif',
|
||||
'else',
|
||||
'endif',
|
||||
'for',
|
||||
'endfor',
|
||||
'trans',
|
||||
'load',
|
||||
'include',
|
||||
'url',
|
||||
]
|
||||
|
||||
pattern = r'{% (\w+)\s'
|
||||
|
||||
err_count = 0
|
||||
|
||||
for idx, line in enumerate(data):
|
||||
for tag in re.findall(pattern, line):
|
||||
if tag not in allowed_tags:
|
||||
print(f" > Line {idx + 1} contains prohibited template tag '{tag}'")
|
||||
err_count += 1
|
||||
|
||||
return err_count
|
||||
|
||||
|
||||
for filename in pathlib.Path(js_i18n_dir).rglob('*.js'):
|
||||
print(f"Checking file 'translated/{os.path.basename(filename)}':")
|
||||
|
||||
with open(filename, 'r') as js_file:
|
||||
data = js_file.readlines()
|
||||
|
||||
errors += check_invalid_tag(data)
|
||||
errors += check_prohibited_tags(data)
|
||||
|
||||
for filename in pathlib.Path(js_dynamic_dir).rglob('*.js'):
|
||||
print(f"Checking file 'dynamic/{os.path.basename(filename)}':")
|
||||
|
||||
# Check that the 'dynamic' files do not contains any translated strings
|
||||
with open(filename, 'r') as js_file:
|
||||
data = js_file.readlines()
|
||||
|
||||
invalid_tags = ['blocktrans', 'blocktranslate', 'trans', 'translate']
|
||||
|
||||
err_count = 0
|
||||
|
||||
for idx, line in enumerate(data):
|
||||
for tag in invalid_tags:
|
||||
tag = '{% ' + tag
|
||||
if tag in line:
|
||||
err_count += 1
|
||||
|
||||
print(f" > Error on line {idx + 1}: Prohibited tag '{tag}' found")
|
||||
|
||||
|
||||
if errors > 0:
|
||||
print(f'Found {errors} incorrect template tags')
|
||||
|
||||
sys.exit(errors)
|
||||
4
.github/scripts/check_migration_files.py
vendored
@@ -20,9 +20,9 @@ for line in str(out.decode()).split('\n'):
|
||||
if len(migrations) == 0:
|
||||
sys.exit(0)
|
||||
|
||||
print(f'There are {len(migrations)} unstaged migration files:')
|
||||
print('There are {n} unstaged migration files:'.format(n=len(migrations)))
|
||||
|
||||
for m in migrations:
|
||||
print(f' - {m}')
|
||||
print(' - {m}'.format(m=m))
|
||||
|
||||
sys.exit(len(migrations))
|
||||
|
||||
100
.github/scripts/check_source_strings.py
vendored
@@ -1,100 +0,0 @@
|
||||
"""Script to check source strings for translations."""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import rapidfuzz
|
||||
|
||||
BACKEND_SOURCE_FILE = [
|
||||
'..',
|
||||
'..',
|
||||
'src',
|
||||
'backend',
|
||||
'InvenTree',
|
||||
'locale',
|
||||
'en',
|
||||
'LC_MESSAGES',
|
||||
'django.po',
|
||||
]
|
||||
|
||||
FRONTEND_SOURCE_FILE = [
|
||||
'..',
|
||||
'..',
|
||||
'src',
|
||||
'frontend',
|
||||
'src',
|
||||
'locales',
|
||||
'en',
|
||||
'messages.po',
|
||||
]
|
||||
|
||||
|
||||
def extract_source_strings(file_path):
|
||||
"""Extract source strings from the provided file."""
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
abs_file_path = os.path.abspath(os.path.join(here, *file_path))
|
||||
|
||||
sources = []
|
||||
|
||||
with open(abs_file_path, encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith('msgid '):
|
||||
msgid = line[6:].strip()
|
||||
|
||||
if msgid in sources:
|
||||
print(f'Duplicate source string: {msgid}')
|
||||
else:
|
||||
sources.append(msgid)
|
||||
|
||||
return sources
|
||||
|
||||
|
||||
def compare_source_strings(sources, threshold):
|
||||
"""Compare source strings to find duplicates (or close matches)."""
|
||||
issues = 0
|
||||
|
||||
for i, source in enumerate(sources):
|
||||
for other in sources[i + 1 :]:
|
||||
if other.lower() == source.lower():
|
||||
print(f'- Duplicate: {source} ~ {other}')
|
||||
issues += 1
|
||||
continue
|
||||
|
||||
ratio = rapidfuzz.fuzz.ratio(source, other)
|
||||
if ratio > threshold:
|
||||
print(f'- Close match: {source} ~ {other} ({ratio:.1f}%)')
|
||||
issues += 1
|
||||
|
||||
if issues:
|
||||
print(f' - Found {issues} issues.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Check source strings for translations.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--backend', action='store_true', help='Check backend source strings'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--frontend', action='store_true', help='Check frontend source strings'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--threshold',
|
||||
type=int,
|
||||
help='Set the threshold for string comparison',
|
||||
default=99,
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.backend:
|
||||
backend_sources = extract_source_strings(BACKEND_SOURCE_FILE)
|
||||
print('Backend source strings:', len(backend_sources))
|
||||
compare_source_strings(backend_sources, args.threshold)
|
||||
|
||||
if args.frontend:
|
||||
frontend_sources = extract_source_strings(FRONTEND_SOURCE_FILE)
|
||||
print('Frontend source strings:', len(frontend_sources))
|
||||
compare_source_strings(frontend_sources, args.threshold)
|
||||
258
.github/scripts/version_check.py
vendored
@@ -10,108 +10,16 @@ tagged branch:
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
|
||||
REPO = os.getenv('GITHUB_REPOSITORY', 'inventree/inventree')
|
||||
GITHUB_API_URL = os.getenv('GITHUB_API_URL', 'https://api.github.com')
|
||||
|
||||
|
||||
def get_src_dir() -> Path:
|
||||
"""Return the path to the InvenTree source directory."""
|
||||
here = Path(__file__).parent.absolute()
|
||||
src_dir = here.joinpath('..', '..', 'src', 'backend', 'InvenTree', 'InvenTree')
|
||||
|
||||
if not src_dir.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Could not find InvenTree source directory: '{src_dir}'"
|
||||
)
|
||||
|
||||
return src_dir
|
||||
|
||||
|
||||
def get_inventree_version() -> str:
|
||||
"""Return the InvenTree version string."""
|
||||
src_dir = get_src_dir()
|
||||
version_file = src_dir.joinpath('version.py')
|
||||
|
||||
if not version_file.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Could not find InvenTree version file: '{version_file}'"
|
||||
)
|
||||
|
||||
with open(version_file, encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
|
||||
# Extract the InvenTree software version
|
||||
results = re.findall(r"""INVENTREE_SW_VERSION = '(.*)'""", text)
|
||||
|
||||
if len(results) != 1:
|
||||
raise ValueError(f'Could not find INVENTREE_SW_VERSION in {version_file}')
|
||||
|
||||
return results[0]
|
||||
|
||||
|
||||
def get_api_version() -> str:
|
||||
"""Return the InvenTree API version string."""
|
||||
src_dir = get_src_dir()
|
||||
api_version_file = src_dir.joinpath('api_version.py')
|
||||
|
||||
if not api_version_file.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Could not find InvenTree API version file: '{api_version_file}'"
|
||||
)
|
||||
|
||||
with open(api_version_file, encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
|
||||
# Extract the InvenTree software version
|
||||
results = re.findall(r"""INVENTREE_API_VERSION = (.*)""", text)
|
||||
|
||||
if len(results) != 1:
|
||||
raise ValueError(
|
||||
f'Could not find INVENTREE_API_VERSION in {api_version_file}'
|
||||
)
|
||||
|
||||
return results[0].strip().strip('"').strip("'")
|
||||
|
||||
|
||||
def version_number_to_tuple(version_string: str) -> tuple[int, int, int, str]:
|
||||
"""Validate a version number string, and convert to a tuple of integers.
|
||||
|
||||
e.g. 1.1.0
|
||||
e.g. 1.1.0 dev
|
||||
e.g. 1.2.3-rc2
|
||||
"""
|
||||
pattern = r'^(\d+)\.(\d+)\.(\d+)[\s-]?(.*)?$'
|
||||
|
||||
match = re.match(pattern, version_string)
|
||||
|
||||
if not match or len(match.groups()) < 3:
|
||||
raise ValueError(
|
||||
f"Version string '{version_string}' did not match required pattern"
|
||||
)
|
||||
|
||||
result = tuple(int(x) for x in match.groups()[:3])
|
||||
|
||||
# Add optional prerelease tag
|
||||
if len(match.groups()) > 3:
|
||||
result += (match.groups()[3] or '',)
|
||||
else:
|
||||
result += ('',)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_existing_release_tags(include_prerelease: bool = True):
|
||||
def get_existing_release_tags():
|
||||
"""Request information on existing releases via the GitHub API."""
|
||||
# Check for github token
|
||||
token = os.getenv('GITHUB_TOKEN', None)
|
||||
@@ -120,7 +28,9 @@ def get_existing_release_tags(include_prerelease: bool = True):
|
||||
if token:
|
||||
headers = {'Authorization': f'Bearer {token}'}
|
||||
|
||||
response = requests.get(f'{GITHUB_API_URL}/repos/{REPO}/releases', headers=headers)
|
||||
response = requests.get(
|
||||
'https://api.github.com/repos/inventree/inventree/releases', headers=headers
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise ValueError(
|
||||
@@ -134,16 +44,13 @@ def get_existing_release_tags(include_prerelease: bool = True):
|
||||
|
||||
for release in data:
|
||||
tag = release['tag_name'].strip()
|
||||
match = re.match(r'^.*(\d+)\.(\d+)\.(\d+).*$', tag)
|
||||
|
||||
version_tuple = version_number_to_tuple(tag)
|
||||
if len(match.groups()) != 3:
|
||||
print(f"Version '{tag}' did not match expected pattern")
|
||||
continue
|
||||
|
||||
if len(version_tuple) >= 4 and version_tuple[3]:
|
||||
# Skip prerelease tags
|
||||
if not include_prerelease:
|
||||
print('-- skipping prerelease tag:', tag)
|
||||
continue
|
||||
|
||||
tags.append(tag)
|
||||
tags.append([int(x) for x in match.groups()])
|
||||
|
||||
return tags
|
||||
|
||||
@@ -155,83 +62,51 @@ def check_version_number(version_string, allow_duplicate=False):
|
||||
"""
|
||||
print(f"Checking version '{version_string}'")
|
||||
|
||||
version_tuple = version_number_to_tuple(version_string)
|
||||
# Check that the version string matches the required format
|
||||
match = re.match(r'^(\d+)\.(\d+)\.(\d+)(?: dev)?$', version_string)
|
||||
|
||||
if not match or len(match.groups()) != 3:
|
||||
raise ValueError(
|
||||
f"Version string '{version_string}' did not match required pattern"
|
||||
)
|
||||
|
||||
version_tuple = [int(x) for x in match.groups()]
|
||||
|
||||
# Look through the existing releases
|
||||
existing = get_existing_release_tags(include_prerelease=False)
|
||||
existing = get_existing_release_tags()
|
||||
|
||||
# Assume that this is the highest release, unless told otherwise
|
||||
highest_release = True
|
||||
|
||||
# A non-standard tag cannot be the 'highest' release
|
||||
if len(version_tuple) >= 4 and version_tuple[3]:
|
||||
highest_release = False
|
||||
print(f"-- Version tag '{version_string}' cannot be the highest release")
|
||||
|
||||
for release in existing:
|
||||
if version_string == release and not allow_duplicate:
|
||||
if release == version_tuple and not allow_duplicate:
|
||||
raise ValueError(f"Duplicate release '{version_string}' exists!")
|
||||
|
||||
release_tuple = version_number_to_tuple(release)
|
||||
|
||||
if release_tuple > version_tuple:
|
||||
if release > version_tuple:
|
||||
highest_release = False
|
||||
print(f'Found newer release: {release!s}')
|
||||
|
||||
if highest_release:
|
||||
print(f"-- Version '{version_string}' is the highest release")
|
||||
print(f'Found newer release: {str(release)}')
|
||||
|
||||
return highest_release
|
||||
|
||||
|
||||
def main() -> bool:
|
||||
"""Run the version check."""
|
||||
parser = argparse.ArgumentParser(description='InvenTree Version Check')
|
||||
parser.add_argument(
|
||||
'--show-version',
|
||||
action='store_true',
|
||||
help='Print the InvenTree version and exit',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--show-api-version',
|
||||
action='store_true',
|
||||
help='Print the InvenTree API version and exit',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--decrement-api',
|
||||
type=str,
|
||||
default='false',
|
||||
help='Decrement the API version by 1 and print',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
inventree_version = get_inventree_version()
|
||||
inventree_api_version = int(get_api_version())
|
||||
|
||||
if args.show_version:
|
||||
print(inventree_version)
|
||||
sys.exit(0)
|
||||
|
||||
if args.show_api_version:
|
||||
if str(args.decrement_api).strip().lower() == 'true':
|
||||
inventree_api_version -= 1
|
||||
print(inventree_api_version)
|
||||
sys.exit(0)
|
||||
|
||||
# Ensure that we are running in GH Actions
|
||||
if os.environ.get('GITHUB_ACTIONS', '') != 'true':
|
||||
print('This script is intended to be run within a GitHub Action!')
|
||||
return False
|
||||
|
||||
print('Running InvenTree version check...')
|
||||
|
||||
if __name__ == '__main__':
|
||||
if 'only_version' in sys.argv:
|
||||
here = Path(__file__).parent.absolute()
|
||||
version_file = here.joinpath(
|
||||
'..', '..', 'src', 'backend', 'InvenTree', 'InvenTree', 'api_version.py'
|
||||
)
|
||||
text = version_file.read_text()
|
||||
results = re.findall(r"""INVENTREE_API_VERSION = (.*)""", text)
|
||||
print(results[0])
|
||||
exit(0)
|
||||
# GITHUB_REF_TYPE may be either 'branch' or 'tag'
|
||||
GITHUB_REF_TYPE = os.environ['GITHUB_REF_TYPE']
|
||||
|
||||
# GITHUB_REF may be either 'refs/heads/<branch>' or 'refs/heads/<tag>'
|
||||
GITHUB_REF = os.environ['GITHUB_REF']
|
||||
|
||||
GITHUB_REF_NAME = os.environ['GITHUB_REF_NAME']
|
||||
|
||||
GITHUB_BASE_REF = os.environ['GITHUB_BASE_REF']
|
||||
|
||||
# Print out version information, makes debugging actions *much* easier!
|
||||
@@ -240,10 +115,26 @@ def main() -> bool:
|
||||
print(f'GITHUB_REF_TYPE: {GITHUB_REF_TYPE}')
|
||||
print(f'GITHUB_BASE_REF: {GITHUB_BASE_REF}')
|
||||
|
||||
print(
|
||||
f"InvenTree Version: '{inventree_version}' - {version_number_to_tuple(inventree_version)}"
|
||||
here = Path(__file__).parent.absolute()
|
||||
version_file = here.joinpath(
|
||||
'..', '..', 'src', 'backend', 'InvenTree', 'InvenTree', 'version.py'
|
||||
)
|
||||
print(f"InvenTree API Version: '{inventree_api_version}'")
|
||||
|
||||
version = None
|
||||
|
||||
with open(version_file, 'r') as f:
|
||||
text = f.read()
|
||||
|
||||
# Extract the InvenTree software version
|
||||
results = re.findall(r"""INVENTREE_SW_VERSION = '(.*)'""", text)
|
||||
|
||||
if len(results) != 1:
|
||||
print(f'Could not find INVENTREE_SW_VERSION in {version_file}')
|
||||
sys.exit(1)
|
||||
|
||||
version = results[0]
|
||||
|
||||
print(f"InvenTree Version: '{version}'")
|
||||
|
||||
# Check version number and look for existing versions
|
||||
# If a release is found which matches the current tag, throw an error
|
||||
@@ -258,63 +149,50 @@ def main() -> bool:
|
||||
if GITHUB_BASE_REF == 'stable':
|
||||
allow_duplicate = True
|
||||
|
||||
highest_release = check_version_number(
|
||||
inventree_version, allow_duplicate=allow_duplicate
|
||||
)
|
||||
highest_release = check_version_number(version, allow_duplicate=allow_duplicate)
|
||||
|
||||
# Determine which docker tag we are going to use
|
||||
docker_tags: Optional[list[str]] = None
|
||||
docker_tags = None
|
||||
|
||||
if GITHUB_REF_TYPE == 'tag':
|
||||
# GITHUB_REF should be of the form /refs/heads/<tag>
|
||||
version_tag: str = GITHUB_REF.split('/')[-1]
|
||||
version_tag = GITHUB_REF.split('/')[-1]
|
||||
print(f"Checking requirements for tagged release - '{version_tag}':")
|
||||
|
||||
if version_tag != inventree_version:
|
||||
print(
|
||||
f"Version number '{inventree_version}' does not match tag '{version_tag}'"
|
||||
)
|
||||
if version_tag != version:
|
||||
print(f"Version number '{version}' does not match tag '{version_tag}'")
|
||||
sys.exit
|
||||
|
||||
docker_tags = [version_tag, 'stable'] if highest_release else [version_tag]
|
||||
if highest_release:
|
||||
docker_tags = [version_tag, 'stable']
|
||||
else:
|
||||
docker_tags = [version_tag]
|
||||
|
||||
elif GITHUB_REF_TYPE == 'branch':
|
||||
# Otherwise we know we are targeting the 'master' branch
|
||||
docker_tags = ['latest']
|
||||
highest_release = False
|
||||
|
||||
else:
|
||||
print('Unsupported branch / version combination:')
|
||||
print(f'InvenTree Version: {inventree_version}')
|
||||
print(f'InvenTree Version: {version}')
|
||||
print('GITHUB_REF_TYPE:', GITHUB_REF_TYPE)
|
||||
print('GITHUB_BASE_REF:', GITHUB_BASE_REF)
|
||||
print('GITHUB_REF:', GITHUB_REF)
|
||||
return False
|
||||
sys.exit(1)
|
||||
|
||||
if docker_tags is None:
|
||||
print('Docker tags could not be determined')
|
||||
return False
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Version check passed for '{inventree_version}'!")
|
||||
print(f"Version check passed for '{version}'!")
|
||||
print(f"Docker tags: '{docker_tags}'")
|
||||
|
||||
target_repos = [REPO.lower(), f'ghcr.io/{REPO.lower()}']
|
||||
|
||||
# Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/
|
||||
with open(os.getenv('GITHUB_ENV'), 'a', encoding='utf-8') as env_file:
|
||||
with open(os.getenv('GITHUB_ENV'), 'a') as env_file:
|
||||
# Construct tag string
|
||||
tag_list = [[f'{r}:{t}' for t in docker_tags] for r in target_repos]
|
||||
tags = ','.join(itertools.chain(*tag_list))
|
||||
tags = ','.join([f'inventree/inventree:{tag}' for tag in docker_tags])
|
||||
|
||||
env_file.write(f'docker_tags={tags}\n')
|
||||
|
||||
if GITHUB_REF_TYPE == 'tag' and highest_release:
|
||||
env_file.write('stable_release=true\n')
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
rslt = main()
|
||||
if rslt is not True:
|
||||
print('Version check failed!')
|
||||
sys.exit(1)
|
||||
|
||||
2
.github/workflows/backport.yaml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
)
|
||||
steps:
|
||||
- name: Backport Action
|
||||
uses: sqren/backport-github-action@ad888e978060bc1b2798690dd9d03c4036560947 # pin@v9.2.2
|
||||
uses: sqren/backport-github-action@f54e19901f2a57f8b82360f2490d47ee82ec82c6 # pin@v9.2.2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
auto_backport_label_prefix: backport-to-
|
||||
|
||||
13
.github/workflows/check_translations.yaml
vendored
@@ -22,8 +22,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INVENTREE_DB_NAME: "./test_db.sqlite"
|
||||
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: INFO
|
||||
INVENTREE_DEBUG: info
|
||||
INVENTREE_MEDIA_ROOT: ./media
|
||||
INVENTREE_STATIC_ROOT: ./static
|
||||
INVENTREE_BACKUP_DIR: ./backup
|
||||
@@ -31,19 +30,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
install: true
|
||||
apt-dependency: gettext
|
||||
- name: Test Translations
|
||||
run: invoke dev.translate
|
||||
- name: Check for Duplicates
|
||||
run: |
|
||||
python ./.github/scripts/check_source_strings.py --frontend --backend
|
||||
run: invoke translate
|
||||
- name: Check Migration Files
|
||||
run: python3 .github/scripts/check_migration_files.py
|
||||
|
||||
106
.github/workflows/docker.yaml
vendored
@@ -39,9 +39,7 @@ jobs:
|
||||
docker: ${{ steps.filter.outputs.docker }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # pin@v3.0.2
|
||||
id: filter
|
||||
with:
|
||||
@@ -55,11 +53,12 @@ jobs:
|
||||
|
||||
# Build the docker image
|
||||
build:
|
||||
name: Docker Build Test
|
||||
needs: paths-filter
|
||||
if: needs.paths-filter.outputs.docker == 'true' || github.event_name == 'release' || github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'full-run')
|
||||
if: needs.paths-filter.outputs.docker == 'true' || github.event_name == 'release' || github.event_name == 'push'
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
python_version: "3.11"
|
||||
@@ -67,14 +66,21 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Set Up Python ${{ env.python_version }}
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # pin@v5.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
python-version: ${{ env.python_version }}
|
||||
- name: Version Check
|
||||
run: |
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||
python3 .github/scripts/version_check.py
|
||||
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
||||
- name: Test Docker Image
|
||||
id: test-docker
|
||||
run: |
|
||||
docker build . --target production --tag inventree-test -f contrib/container/Dockerfile
|
||||
docker run --rm inventree-test invoke version
|
||||
docker run --rm inventree-test invoke --version
|
||||
docker run --rm inventree-test invoke --list
|
||||
docker run --rm inventree-test gunicorn --version
|
||||
@@ -90,11 +96,8 @@ jobs:
|
||||
- name: Update Docker Image
|
||||
run: |
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke install
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke version
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke update
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke backup
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke restore
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke dev.setup-dev
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke setup-dev
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml up -d
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke wait
|
||||
- name: Check Data Directory
|
||||
@@ -109,90 +112,42 @@ jobs:
|
||||
test -f data/config.yaml
|
||||
test -f data/plugins.txt
|
||||
test -f data/secret_key.txt
|
||||
test -f data/oidc.pem
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> contrib/container/docker.dev.env
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.test --disable-pty --translations
|
||||
|
||||
# Run migration test
|
||||
migration_test:
|
||||
name: Migration Test
|
||||
needs: paths-filter
|
||||
if: needs.paths-filter.outputs.docker == 'true' || github.event_name == 'release' || github.event_name == 'push'
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
python_version: "3.11"
|
||||
runs-on: ubuntu-latest # in the future we can try to use alternative runners here
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run Migration Tests
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke test --disable-pty
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run inventree-dev-server invoke test --migrations --disable-pty
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml down
|
||||
- name: Clean up test folder
|
||||
run: |
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke update
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.setup-dev
|
||||
docker compose --project-directory . -f contrib/container/dev-docker-compose.yml run --rm inventree-dev-server invoke dev.test --migrations --translations
|
||||
|
||||
# Build and publish
|
||||
publish:
|
||||
name: Publish Docker Image
|
||||
needs: [build, migration_test]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
python_version: "3.11"
|
||||
runs-on: ubuntu-latest # in the future we can try to use alternative runners here
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set Up Python ${{ env.python_version }}
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # pin@v6.0.0
|
||||
with:
|
||||
python-version: ${{ env.python_version }}
|
||||
- name: Version Check
|
||||
run: |
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||
python3 .github/scripts/version_check.py
|
||||
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
||||
rm -rf InvenTree/_testfolder
|
||||
- name: Set up QEMU
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # pin@v3.6.0
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # pin@v3.0.0
|
||||
- name: Set up Docker Buildx
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # pin@v3.11.1
|
||||
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # pin@v3.3.0
|
||||
- name: Set up cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # pin@v4.0.0
|
||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # pin@v3.5.0
|
||||
- name: Check if Dockerhub login is required
|
||||
id: docker_login
|
||||
run: |
|
||||
if [ -z "${{ secrets.DOCKER_USERNAME }}" ]; then
|
||||
echo "skip_dockerhub_login=true" >> $GITHUB_OUTPUT
|
||||
echo "skip_dockerhub_login=true" >> $GITHUB_ENV
|
||||
else
|
||||
echo "skip_dockerhub_login=false" >> $GITHUB_OUTPUT
|
||||
echo "skip_dockerhub_login=false" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Login to Dockerhub
|
||||
if: github.event_name != 'pull_request' && steps.docker_login.outputs.skip_dockerhub_login != 'true'
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # pin@v3.6.0
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # pin@v3.1.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Log into registry ghcr.io
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # pin@v3.6.0
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # pin@v3.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -201,18 +156,17 @@ jobs:
|
||||
- name: Extract Docker metadata
|
||||
if: github.event_name != 'pull_request'
|
||||
id: meta
|
||||
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # pin@v5.8.0
|
||||
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # pin@v5.5.1
|
||||
with:
|
||||
images: |
|
||||
inventree/inventree
|
||||
ghcr.io/${{ github.repository }}
|
||||
- uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5 # pin@v1
|
||||
|
||||
- name: Push Docker Images
|
||||
id: push-docker
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: depot/build-push-action@9785b135c3c76c33db102e45be96a25ab55cd507 # pin@v1
|
||||
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # pin@v5.3.0
|
||||
with:
|
||||
project: jczzbjkk68
|
||||
context: .
|
||||
file: ./contrib/container/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
407
.github/workflows/qc_checks.yaml
vendored
@@ -10,18 +10,19 @@ on:
|
||||
|
||||
env:
|
||||
python_version: 3.9
|
||||
node_version: 20
|
||||
node_version: 18
|
||||
# The OS version must be set per job
|
||||
server_start_sleep: 60
|
||||
requests_version: 2.31.0
|
||||
pyyaml_version: 6.0.1
|
||||
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_DB_NAME: inventree
|
||||
INVENTREE_MEDIA_ROOT: /home/runner/work/InvenTree/test_inventree_media
|
||||
INVENTREE_STATIC_ROOT: /home/runner/work/InvenTree/test_inventree_static
|
||||
INVENTREE_BACKUP_DIR: /home/runner/work/InvenTree/test_inventree_backup
|
||||
INVENTREE_MEDIA_ROOT: ../test_inventree_media
|
||||
INVENTREE_STATIC_ROOT: ../test_inventree_static
|
||||
INVENTREE_BACKUP_DIR: ../test_inventree_backup
|
||||
INVENTREE_SITE_URL: http://localhost:8000
|
||||
INVENTREE_DEBUG: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -37,13 +38,9 @@ jobs:
|
||||
frontend: ${{ steps.filter.outputs.frontend }}
|
||||
api: ${{ steps.filter.outputs.api }}
|
||||
force: ${{ steps.force.outputs.force }}
|
||||
cicd: ${{ steps.filter.outputs.cicd }}
|
||||
requirements: ${{ steps.filter.outputs.requirements }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # pin@v3.0.2
|
||||
id: filter
|
||||
with:
|
||||
@@ -61,13 +58,6 @@ jobs:
|
||||
- 'src/backend/InvenTree/InvenTree/api_version.py'
|
||||
frontend:
|
||||
- 'src/frontend/**'
|
||||
cicd:
|
||||
- '.github/workflows/**'
|
||||
requirements:
|
||||
- 'src/backend/requirements.txt'
|
||||
- 'src/backend/requirements-dev.txt'
|
||||
- 'docs/requirements.txt'
|
||||
- 'contrib/dev_reqs/requirements.txt'
|
||||
- name: Is CI being forced?
|
||||
run: echo "force=true" >> $GITHUB_OUTPUT
|
||||
id: force
|
||||
@@ -75,18 +65,38 @@ jobs:
|
||||
contains(github.event.pull_request.labels.*.name, 'dependency') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'full-run')
|
||||
|
||||
pre-commit:
|
||||
name: Style [pre-commit]
|
||||
runs-on: ubuntu-24.04
|
||||
needs: paths-filter
|
||||
if: needs.paths-filter.outputs.cicd == 'true' || needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.requirements == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
javascript:
|
||||
name: Style - Classic UI [JS]
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
needs: ["pre-commit"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
persist-credentials: false
|
||||
npm: true
|
||||
install: true
|
||||
- name: Check Templated JS Files
|
||||
run: |
|
||||
cd .github/scripts
|
||||
python3 check_js_templates.py
|
||||
- name: Lint Javascript Files
|
||||
run: |
|
||||
python src/backend/InvenTree/manage.py prerender
|
||||
cd src/backend && npx eslint InvenTree/InvenTree/static_i18n/i18n/*.js
|
||||
|
||||
pre-commit:
|
||||
name: Style [pre-commit]
|
||||
runs-on: ubuntu-20.04
|
||||
needs: paths-filter
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Set up Python ${{ env.python_version }}
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # pin@v6.0.0
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # pin@v5.1.0
|
||||
with:
|
||||
python-version: ${{ env.python_version }}
|
||||
cache: "pip"
|
||||
@@ -97,40 +107,17 @@ jobs:
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||
python3 .github/scripts/version_check.py
|
||||
|
||||
typecheck:
|
||||
name: Style [Typecheck]
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [paths-filter, pre-commit]
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.requirements == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Environment Setup
|
||||
id: setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
apt-dependency: gettext poppler-utils
|
||||
dev-install: true
|
||||
update: true
|
||||
- name: Check types
|
||||
run: |
|
||||
ty check --python ${Python_ROOT_DIR}/bin/python3
|
||||
|
||||
mkdocs:
|
||||
name: Style [Documentation]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
needs: paths-filter
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Set up Python ${{ env.python_version }}
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # pin@v6.0.0
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # pin@v5.1.0
|
||||
with:
|
||||
python-version: ${{ env.python_version }}
|
||||
- name: Check Config
|
||||
@@ -139,7 +126,7 @@ jobs:
|
||||
pip install --require-hashes -r docs/requirements.txt
|
||||
python docs/ci/check_mkdocs_config.py
|
||||
- name: Check Links
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # pin@v1
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1
|
||||
with:
|
||||
folder-path: docs
|
||||
config-file: docs/mlc_config.json
|
||||
@@ -148,7 +135,7 @@ jobs:
|
||||
|
||||
schema:
|
||||
name: Tests - API Schema Documentation
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: paths-filter
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
env:
|
||||
@@ -164,9 +151,7 @@ jobs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -174,121 +159,74 @@ jobs:
|
||||
dev-install: true
|
||||
update: true
|
||||
- name: Export API Documentation
|
||||
run: invoke dev.schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
|
||||
run: invoke schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
|
||||
- name: Upload schema
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # pin@v4.3.3
|
||||
with:
|
||||
name: schema.yml
|
||||
path: src/backend/InvenTree/schema.yml
|
||||
- name: Download public schema
|
||||
env:
|
||||
API: ${{ needs.paths-filter.outputs.api }}
|
||||
if: needs.paths-filter.outputs.api == 'false'
|
||||
run: |
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
|
||||
version="$(python3 .github/scripts/version_check.py --show-api-version --decrement-api=${API} 2>&1)"
|
||||
echo "API Version: $version"
|
||||
version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
|
||||
echo "Version: $version"
|
||||
url="https://raw.githubusercontent.com/inventree/schema/main/export/${version}/api.yaml"
|
||||
echo "URL: $url"
|
||||
code=$(curl -s -o api.yaml $url --write-out '%{http_code}' --silent)
|
||||
if [ "$code" != "200" ]; then
|
||||
exit 1
|
||||
fi
|
||||
curl -s -o api.yaml $url
|
||||
echo "Downloaded api.yaml"
|
||||
- name: Running OpenAPI Spec diff action
|
||||
id: breaking_changes
|
||||
uses: oasdiff/oasdiff-action/diff@1c611ffb1253a72924624aa4fb662e302b3565d3 # pin@main
|
||||
with:
|
||||
base: "api.yaml"
|
||||
revision: "src/backend/InvenTree/schema.yml"
|
||||
format: "html"
|
||||
- name: Echoing diff to step
|
||||
continue-on-error: true
|
||||
env:
|
||||
DIFF: ${{ steps.breaking_changes.outputs.diff }}
|
||||
run: echo "${DIFF}" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Check for differences in API Schema
|
||||
if: needs.paths-filter.outputs.api == 'false'
|
||||
run: |
|
||||
diff --color -u src/backend/InvenTree/schema.yml api.yaml
|
||||
diff -u src/backend/InvenTree/schema.yml api.yaml && echo "no difference in API schema " || exit 2
|
||||
- name: Check schema - including warnings
|
||||
run: invoke dev.schema
|
||||
run: invoke schema
|
||||
continue-on-error: true
|
||||
- name: Extract version for publishing
|
||||
id: version
|
||||
if: github.ref == 'refs/heads/master' && needs.paths-filter.outputs.api == 'true'
|
||||
run: |
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
|
||||
version="$(python3 .github/scripts/version_check.py --show-api-version 2>&1)"
|
||||
echo "API Version: $version"
|
||||
version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
|
||||
echo "Version: $version"
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
- name: Extract settings / tags
|
||||
run: invoke int.export-definitions --basedir docs
|
||||
- name: Upload settings
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
with:
|
||||
name: inventree_settings.json
|
||||
path: docs/generated/inventree_settings.json
|
||||
- name: Upload tags
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
with:
|
||||
name: inventree_tags.yml
|
||||
path: docs/generated/inventree_tags.yml
|
||||
- name: Upload filters
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
with:
|
||||
name: inventree_filters.yml
|
||||
path: docs/generated/inventree_filters.yml
|
||||
|
||||
schema-push:
|
||||
name: Push new schema
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [paths-filter, schema]
|
||||
if: needs.schema.result == 'success' && github.ref == 'refs/heads/master' && needs.paths-filter.outputs.api == 'true' && github.repository_owner == 'inventree'
|
||||
env:
|
||||
version: ${{ needs.schema.outputs.version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
name: Checkout Code
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
repository: inventree/schema
|
||||
token: ${{ secrets.SCHEMA_PAT }}
|
||||
persist-credentials: true
|
||||
- name: Create artifact directory
|
||||
run: mkdir -p artifact
|
||||
- name: Download schema artifact
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # pin@v6.0.0
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
path: artifact
|
||||
merge-multiple: true
|
||||
- name: Move files to correct location
|
||||
name: schema.yml
|
||||
- name: Move schema to correct location
|
||||
run: |
|
||||
echo "Version: ${version}"
|
||||
echo "before move"
|
||||
ls -la artifact
|
||||
echo "Version: $version"
|
||||
mkdir export/${version}
|
||||
mv artifact/schema.yml export/${version}/api.yaml
|
||||
mv artifact/inventree_settings.json export/${version}/inventree_settings.json
|
||||
mv artifact/inventree_tags.yml export/${version}/inventree_tags.yml
|
||||
mv artifact/inventree_filters.yml export/${version}/inventree_filters.yml
|
||||
echo "after move"
|
||||
ls -la artifact
|
||||
rm -rf artifact
|
||||
- uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # pin@v7.0.0
|
||||
name: Commit schema changes
|
||||
mv schema.yml export/${version}/api.yaml
|
||||
- uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1
|
||||
with:
|
||||
commit_message: "Update API schema for ${{ env.version }} / ${{ github.sha }}"
|
||||
commit_message: "Update API schema for ${version}"
|
||||
|
||||
python:
|
||||
name: Tests - inventree-python
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
needs: ["pre-commit", "paths-filter"]
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
|
||||
env:
|
||||
WRAPPER_NAME: inventree-python
|
||||
wrapper_name: inventree-python
|
||||
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
|
||||
INVENTREE_DB_NAME: ../inventree_unit_test_db.sqlite3
|
||||
INVENTREE_ADMIN_USER: testuser
|
||||
@@ -298,57 +236,50 @@ jobs:
|
||||
INVENTREE_PYTHON_TEST_USERNAME: testuser
|
||||
INVENTREE_PYTHON_TEST_PASSWORD: testpassword
|
||||
INVENTREE_SITE_URL: http://127.0.0.1:12345
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: WARNING
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: true
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
apt-dependency: gettext poppler-utils
|
||||
dev-install: true
|
||||
update: true
|
||||
- name: Download Python Code For `${WRAPPER_NAME}`
|
||||
run: git clone --depth 1 https://github.com/inventree/${WRAPPER_NAME} ./${WRAPPER_NAME}
|
||||
npm: 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 dev.delete-data -f
|
||||
invoke dev.import-fixtures
|
||||
invoke dev.server -a 127.0.0.1:12345 &
|
||||
invoke delete-data -f
|
||||
invoke import-fixtures
|
||||
invoke server -a 127.0.0.1:12345 &
|
||||
invoke wait
|
||||
- name: Run Tests For `${WRAPPER_NAME}`
|
||||
- name: Run Tests For `${{ env.wrapper_name }}`
|
||||
run: |
|
||||
cd ${WRAPPER_NAME}
|
||||
cd ${{ env.wrapper_name }}
|
||||
invoke check-server
|
||||
coverage run -m unittest discover -s test/
|
||||
|
||||
coverage:
|
||||
name: Tests - DB [SQLite] + Coverage ${{ matrix.python_version }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
needs: ["pre-commit", "paths-filter"]
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
continue-on-error: true # continue if a step fails so that coverage gets pushed
|
||||
strategy:
|
||||
matrix:
|
||||
python_version: [3.9]
|
||||
# python_version: [3.9, 3.12] # Disabled due to requirement issues
|
||||
python_version: [3.9, 3.12]
|
||||
|
||||
env:
|
||||
INVENTREE_DB_NAME: ./inventree.sqlite
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_PLUGINS_ENABLED: true
|
||||
INVENTREE_CONSOLE_LOG: false
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
python_version: ${{ matrix.python_version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -358,19 +289,13 @@ jobs:
|
||||
- name: Data Export Test
|
||||
uses: ./.github/actions/migration
|
||||
- name: Test Translations
|
||||
run: invoke dev.translate
|
||||
run: invoke translate
|
||||
- name: Check Migration Files
|
||||
run: python3 .github/scripts/check_migration_files.py
|
||||
- name: Coverage Tests
|
||||
run: invoke dev.test --check --coverage --translations
|
||||
- name: Upload raw coverage to artifacts
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
with:
|
||||
name: coverage
|
||||
path: .coverage
|
||||
retention-days: 14
|
||||
run: invoke test --coverage
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # pin@v5.5.1
|
||||
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # pin@v4.3.1
|
||||
if: always()
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -379,7 +304,7 @@ jobs:
|
||||
|
||||
postgres:
|
||||
name: Tests - DB [PostgreSQL]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
needs: ["pre-commit", "paths-filter"]
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
|
||||
@@ -389,9 +314,7 @@ jobs:
|
||||
INVENTREE_DB_PASSWORD: password
|
||||
INVENTREE_DB_HOST: "127.0.0.1"
|
||||
INVENTREE_DB_PORT: 5432
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: INFO
|
||||
INVENTREE_CONSOLE_LOG: false
|
||||
INVENTREE_DEBUG: info
|
||||
INVENTREE_CACHE_HOST: localhost
|
||||
INVENTREE_PLUGINS_ENABLED: true
|
||||
|
||||
@@ -405,14 +328,12 @@ jobs:
|
||||
- 5432:5432
|
||||
|
||||
redis:
|
||||
image: redis:8
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -421,13 +342,13 @@ jobs:
|
||||
dev-install: true
|
||||
update: true
|
||||
- name: Run Tests
|
||||
run: invoke dev.test --check --translations
|
||||
run: invoke test
|
||||
- name: Data Export Test
|
||||
uses: ./.github/actions/migration
|
||||
|
||||
mysql:
|
||||
name: Tests - DB [MySQL]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
needs: ["pre-commit", "paths-filter"]
|
||||
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
@@ -439,14 +360,12 @@ jobs:
|
||||
INVENTREE_DB_PASSWORD: password
|
||||
INVENTREE_DB_HOST: "127.0.0.1"
|
||||
INVENTREE_DB_PORT: 3306
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: WARNING
|
||||
INVENTREE_CONSOLE_LOG: false
|
||||
INVENTREE_DEBUG: info
|
||||
INVENTREE_PLUGINS_ENABLED: true
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:9
|
||||
image: mysql:latest
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: ${{ env.INVENTREE_DB_NAME }}
|
||||
@@ -458,9 +377,7 @@ jobs:
|
||||
- 3306:3306
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -469,7 +386,7 @@ jobs:
|
||||
dev-install: true
|
||||
update: true
|
||||
- name: Run Tests
|
||||
run: invoke dev.test --check --translations
|
||||
run: invoke test
|
||||
- name: Data Export Test
|
||||
uses: ./.github/actions/migration
|
||||
|
||||
@@ -486,8 +403,7 @@ jobs:
|
||||
INVENTREE_DB_PASSWORD: password
|
||||
INVENTREE_DB_HOST: "127.0.0.1"
|
||||
INVENTREE_DB_PORT: 5432
|
||||
INVENTREE_DEBUG: False
|
||||
INVENTREE_LOG_LEVEL: WARNING
|
||||
INVENTREE_DEBUG: info
|
||||
INVENTREE_PLUGINS_ENABLED: false
|
||||
|
||||
services:
|
||||
@@ -500,9 +416,7 @@ jobs:
|
||||
- 5432:5432
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -511,9 +425,9 @@ jobs:
|
||||
dev-install: true
|
||||
update: true
|
||||
- name: Run Tests
|
||||
run: invoke dev.test --check --migrations --report --coverage --translations
|
||||
run: invoke test --migrations --report --coverage
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # pin@v5.5.1
|
||||
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # pin@v4.3.1
|
||||
if: always()
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -529,14 +443,11 @@ jobs:
|
||||
env:
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_DB_NAME: /home/runner/work/InvenTree/db.sqlite3
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: WARNING
|
||||
INVENTREE_DEBUG: info
|
||||
INVENTREE_PLUGINS_ENABLED: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
name: Checkout Code
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
@@ -545,6 +456,12 @@ jobs:
|
||||
- name: Fetch Database
|
||||
run: git clone --depth 1 https://github.com/inventree/test-db ./test-db
|
||||
|
||||
- name: Latest Database
|
||||
run: |
|
||||
cp test-db/latest.sqlite3 /home/runner/work/InvenTree/db.sqlite3
|
||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||
invoke migrate
|
||||
|
||||
- name: 0.10.0 Database
|
||||
run: |
|
||||
rm /home/runner/work/InvenTree/db.sqlite3
|
||||
@@ -559,6 +476,13 @@ jobs:
|
||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||
invoke migrate
|
||||
|
||||
- name: 0.12.0 Database
|
||||
run: |
|
||||
rm /home/runner/work/InvenTree/db.sqlite3
|
||||
cp test-db/stable_0.12.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
|
||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||
invoke migrate
|
||||
|
||||
- name: 0.13.5 Database
|
||||
run: |
|
||||
rm /home/runner/work/InvenTree/db.sqlite3
|
||||
@@ -566,106 +490,62 @@ jobs:
|
||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||
invoke migrate
|
||||
|
||||
- name: 0.16.0 Database
|
||||
run: |
|
||||
rm /home/runner/work/InvenTree/db.sqlite3
|
||||
cp test-db/stable_0.16.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
|
||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||
invoke migrate
|
||||
|
||||
- name: 0.17.0 Database
|
||||
run: |
|
||||
rm /home/runner/work/InvenTree/db.sqlite3
|
||||
cp test-db/stable_0.17.0.sqlite3 /home/runner/work/InvenTree/db.sqlite3
|
||||
chmod +rw /home/runner/work/InvenTree/db.sqlite3
|
||||
invoke migrate
|
||||
|
||||
web_ui:
|
||||
name: Tests - Web UI
|
||||
runs-on: ubuntu-24.04
|
||||
platform_ui:
|
||||
name: Tests - Platform UI
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 60
|
||||
needs: ["pre-commit", "paths-filter"]
|
||||
if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
env:
|
||||
POSTGRES_DB: inventree
|
||||
POSTGRES_USER: inventree_user
|
||||
POSTGRES_PASSWORD: inventree_password
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U testuser"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
env:
|
||||
INVENTREE_DB_ENGINE: postgresql
|
||||
INVENTREE_DB_NAME: inventree
|
||||
INVENTREE_DB_HOST: "127.0.0.1"
|
||||
INVENTREE_DB_PORT: 5432
|
||||
INVENTREE_DB_USER: inventree_user
|
||||
INVENTREE_DB_PASSWORD: inventree_password
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_DB_NAME: /home/runner/work/InvenTree/db.sqlite3
|
||||
INVENTREE_DEBUG: True
|
||||
INVENTREE_PLUGINS_ENABLED: false
|
||||
VITE_COVERAGE_BUILD: true
|
||||
VITE_COVERAGE: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
npm: true
|
||||
install: true
|
||||
update: true
|
||||
apt-dependency: postgresql-client libpq-dev
|
||||
pip-dependency: psycopg2
|
||||
- name: Set up test data
|
||||
run: |
|
||||
invoke dev.setup-test -iv
|
||||
invoke int.rebuild-thumbnails
|
||||
run: invoke setup-test -i
|
||||
- name: Rebuild thumbnails
|
||||
run: invoke rebuild-thumbnails
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
invoke int.frontend-compile --extract
|
||||
cd src/frontend && npx playwright install --with-deps
|
||||
run: inv frontend-compile
|
||||
- name: Install Playwright Browsers
|
||||
run: cd src/frontend && npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
id: tests
|
||||
run: cd src/frontend && npx nyc playwright test
|
||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # pin@v4
|
||||
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
||||
with:
|
||||
name: playwright-report
|
||||
path: src/frontend/playwright-report/
|
||||
retention-days: 14
|
||||
- name: Report coverage
|
||||
if: always()
|
||||
run: cd src/frontend && npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --exclude-after-remap false
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # pin@v5.5.1
|
||||
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # pin@v4.3.1
|
||||
if: always()
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: inventree/InvenTree
|
||||
flags: web
|
||||
- name: Upload bundler info
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
cd src/frontend
|
||||
yarn install
|
||||
yarn run build
|
||||
flags: pui
|
||||
|
||||
web_ui_build:
|
||||
name: Build - Web UI
|
||||
runs-on: ubuntu-24.04
|
||||
platform_ui_build:
|
||||
name: Build - UI Platform
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -674,38 +554,11 @@ jobs:
|
||||
run: cd src/frontend && yarn install
|
||||
- name: Build frontend
|
||||
run: cd src/frontend && yarn run compile && yarn run build
|
||||
- name: Write version file - SHA
|
||||
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
|
||||
- name: Zip frontend
|
||||
run: |
|
||||
cd src/backend/InvenTree/web/static
|
||||
zip -r frontend-build.zip web/ web/.vite
|
||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # pin@v5.0.0
|
||||
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # pin@v4.3.3
|
||||
with:
|
||||
name: frontend-build
|
||||
path: src/backend/InvenTree/web/static/web
|
||||
include-hidden-files: true
|
||||
|
||||
zizmor:
|
||||
name: Security [Zizmor]
|
||||
runs-on: ubuntu-24.04
|
||||
needs: ["pre-commit", "paths-filter"]
|
||||
if: needs.paths-filter.outputs.cicd == 'true' || needs.paths-filter.outputs.force == 'true'
|
||||
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817 # pin@v2
|
||||
- name: Run zizmor
|
||||
run: uvx zizmor --format sarif . > results.sarif
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # pin@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: zizmor
|
||||
|
||||
100
.github/workflows/release.yaml
vendored
@@ -1,18 +1,13 @@
|
||||
# Runs on releases
|
||||
|
||||
name: Publish release
|
||||
name: Publish release notes
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
python_version: 3.9
|
||||
|
||||
jobs:
|
||||
stable:
|
||||
runs-on: ubuntu-24.04
|
||||
name: Write release to stable branch
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
@@ -20,32 +15,26 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Version Check
|
||||
run: |
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||
python3 .github/scripts/version_check.py
|
||||
- name: Push to Stable Branch
|
||||
uses: ad-m/github-push-action@77c5b412c50b723d2a4fbc6d71fb5723bcd439aa # pin@v1.0.0
|
||||
uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # pin@v0.8.0
|
||||
if: env.stable_release == 'true'
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: stable
|
||||
force: true
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
name: Build and attest frontend
|
||||
publish-build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
attestations: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
@@ -54,83 +43,14 @@ jobs:
|
||||
run: cd src/frontend && yarn install
|
||||
- name: Build frontend
|
||||
run: cd src/frontend && npm run compile && npm run build
|
||||
- name: Create SBOM for frontend
|
||||
uses: anchore/sbom-action@8e94d75ddd33f69f691467e42275782e4bfefe84 # pin@v0
|
||||
with:
|
||||
artifact-name: frontend-build.spdx
|
||||
path: src/frontend
|
||||
- name: Write version file - SHA
|
||||
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
|
||||
- name: Write version file - TAG
|
||||
run: cd src/backend/InvenTree/web/static/web/.vite && echo "${REF_NAME}" > tag.txt
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
- name: Zip frontend
|
||||
run: |
|
||||
cd src/backend/InvenTree/web/static/web
|
||||
zip -r ../frontend-build.zip * .vite
|
||||
- name: Attest Build Provenance
|
||||
id: attest
|
||||
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # pin@v1
|
||||
with:
|
||||
subject-path: "${{ github.workspace }}/src/backend/InvenTree/web/static/frontend-build.zip"
|
||||
|
||||
- name: Upload frontend
|
||||
uses: svenstaro/upload-release-action@81c65b7cd4de9b2570615ce3aad67a41de5b1a13 # pin@2.11.2
|
||||
zip -r ../frontend-build.zip *
|
||||
- uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # pin@2.9.0
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: src/backend/InvenTree/web/static/frontend-build.zip
|
||||
asset_name: frontend-build.zip
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
- name: Upload Attestation
|
||||
uses: svenstaro/upload-release-action@81c65b7cd4de9b2570615ce3aad67a41de5b1a13 # pin@2.11.2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
asset_name: frontend-build.intoto.jsonl
|
||||
file: ${{ steps.attest.outputs.bundle-path}}
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
docs:
|
||||
runs-on: ubuntu-24.04
|
||||
name: Build and publish documentation
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
INVENTREE_DB_ENGINE: sqlite3
|
||||
INVENTREE_DB_NAME: inventree
|
||||
INVENTREE_MEDIA_ROOT: /home/runner/work/InvenTree/test_inventree_media
|
||||
INVENTREE_STATIC_ROOT: /home/runner/work/InvenTree/test_inventree_static
|
||||
INVENTREE_BACKUP_DIR: /home/runner/work/InvenTree/test_inventree_backup
|
||||
INVENTREE_SITE_URL: http://localhost:8000
|
||||
INVENTREE_DEBUG: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
install: true
|
||||
npm: true
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||
pip install --require-hashes -r docs/requirements.txt
|
||||
- name: Build documentation
|
||||
run: |
|
||||
invoke build-docs --mkdocs
|
||||
- name: Zip build docs
|
||||
run: |
|
||||
cd docs/site
|
||||
zip -r docs-html.zip *
|
||||
- name: Publish documentation
|
||||
uses: svenstaro/upload-release-action@81c65b7cd4de9b2570615ce3aad67a41de5b1a13 # pin@2.11.2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: docs/site/docs-html.zip
|
||||
asset_name: docs-html.zip
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
8
.github/workflows/scorecard.yaml
vendored
@@ -32,12 +32,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -67,6 +67,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v4.31.0
|
||||
uses: github/codeql-action/upload-sarif@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
2
.github/workflows/stale.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # pin@v10.1.0
|
||||
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # pin@v9.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "This issue seems stale. Please react to show this is still important."
|
||||
|
||||
49
.github/workflows/translations.yaml
vendored
@@ -7,24 +7,22 @@ on:
|
||||
|
||||
env:
|
||||
python_version: 3.9
|
||||
node_version: 20
|
||||
node_version: 18
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
synchronize-with-crowdin:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INVENTREE_DB_NAME: "./test_db.sqlite"
|
||||
INVENTREE_DB_ENGINE: django.db.backends.sqlite3
|
||||
INVENTREE_DEBUG: true
|
||||
INVENTREE_LOG_LEVEL: INFO
|
||||
INVENTREE_DEBUG: info
|
||||
INVENTREE_MEDIA_ROOT: ./media
|
||||
INVENTREE_STATIC_ROOT: ./static
|
||||
INVENTREE_BACKUP_DIR: ./backup
|
||||
@@ -32,42 +30,25 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # pin@v5.0.0
|
||||
with:
|
||||
persist-credentials: true
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # pin@v4.1.5
|
||||
- name: Environment Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
install: true
|
||||
npm: true
|
||||
apt-dependency: gettext
|
||||
- name: Make Translations
|
||||
run: invoke dev.translate
|
||||
- name: Remove compiled static files
|
||||
run: rm -rf src/backend/InvenTree/static
|
||||
- name: Remove all local changes that are not *.po files
|
||||
run: invoke translate
|
||||
- name: Commit files
|
||||
run: |
|
||||
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add src/backend/InvenTree/locale/en/LC_MESSAGES/django.po src/frontend/src/locales/en/messages.po
|
||||
echo "Adding commit (or ignoring if no changes)"
|
||||
git commit -m "add translations" || true
|
||||
echo "Removing all other changes"
|
||||
git reset --hard
|
||||
echo "Resetting to HEAD~"
|
||||
git reset HEAD~ || true
|
||||
- name: crowdin action
|
||||
uses: crowdin/github-action@08713f00a50548bfe39b37e8f44afb53e7a802d4 # pin@v2
|
||||
git checkout -b l10_local
|
||||
git add "*.po"
|
||||
git commit -m "updated translation base"
|
||||
- name: Push changes
|
||||
uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # pin@v0.8.0
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
localization_branch_name: l10_crowdin
|
||||
create_pull_request: true
|
||||
pull_request_title: 'New Crowdin updates'
|
||||
pull_request_body: 'New Crowdin translations by [Crowdin GH Action](https://github.com/crowdin/github-action)'
|
||||
pull_request_base_branch_name: 'master'
|
||||
pull_request_labels: 'translations'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: l10
|
||||
force: true
|
||||
|
||||
4
.github/workflows/update.yml.disabled
vendored
@@ -9,9 +9,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1
|
||||
- name: Setup
|
||||
run: pip install --require-hashes -r requirements-dev.txt
|
||||
- name: Update requirements.txt
|
||||
|
||||
19
.gitignore
vendored
@@ -7,7 +7,6 @@ __pycache__/
|
||||
.Python
|
||||
env/
|
||||
inventree-env/
|
||||
.venv/
|
||||
./build/
|
||||
.cache/
|
||||
develop-eggs/
|
||||
@@ -19,6 +18,7 @@ share/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
@@ -31,7 +31,6 @@ var/
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*.sqlite3-journal
|
||||
*.backup
|
||||
@@ -46,17 +45,18 @@ inventree_media
|
||||
inventree_static
|
||||
static_i18n
|
||||
|
||||
# Local config files
|
||||
# Local config file
|
||||
config.yaml
|
||||
plugins.txt
|
||||
secret_key.txt
|
||||
oidc.pem
|
||||
|
||||
# Default data file
|
||||
data.json
|
||||
*.json.tmp
|
||||
*.tmp.json
|
||||
|
||||
# Key file
|
||||
secret_key.txt
|
||||
|
||||
# IDE / development files
|
||||
.idea/
|
||||
*.code-workspace
|
||||
@@ -80,7 +80,6 @@ js_tmp/
|
||||
|
||||
# Development files
|
||||
dev/
|
||||
dev-db/
|
||||
data/
|
||||
env/
|
||||
|
||||
@@ -88,10 +87,6 @@ env/
|
||||
src/backend/InvenTree/InvenTree/locale_stats.json
|
||||
src/backend/InvenTree/InvenTree/licenses.txt
|
||||
|
||||
# Logs
|
||||
src/backend/InvenTree/logs.json
|
||||
src/backend/InvenTree/logs.log
|
||||
|
||||
# node.js
|
||||
node_modules/
|
||||
|
||||
@@ -111,3 +106,7 @@ api.yaml
|
||||
# web frontend (static files)
|
||||
src/backend/InvenTree/web/static
|
||||
InvenTree/web/static
|
||||
|
||||
# Generated docs files
|
||||
docs/docs/api/*.yml
|
||||
docs/docs/api/schema/*.yml
|
||||
|
||||
18
.pkgr.yml
@@ -2,8 +2,10 @@ name: inventree
|
||||
description: Open Source Inventory Management System
|
||||
homepage: https://inventree.org
|
||||
notifications: true
|
||||
buildpack: https://github.com/matmair/null-buildpack#master
|
||||
buildpack: https://github.com/mjmair/heroku-buildpack-python#v216-mjmair
|
||||
env:
|
||||
- STACK=heroku-20
|
||||
- DISABLE_COLLECTSTATIC=1
|
||||
- INVENTREE_DB_ENGINE=sqlite3
|
||||
- INVENTREE_DB_NAME=database.sqlite3
|
||||
- INVENTREE_PLUGINS_ENABLED
|
||||
@@ -12,17 +14,14 @@ env:
|
||||
- INVENTREE_BACKUP_DIR=/opt/inventree/backup
|
||||
- INVENTREE_PLUGIN_FILE=/opt/inventree/plugins.txt
|
||||
- INVENTREE_CONFIG_FILE=/opt/inventree/config.yaml
|
||||
- APP_REPO=inventree/InvenTree
|
||||
before_install: contrib/packager.io/preinstall.sh
|
||||
after_install: contrib/packager.io/postinstall.sh
|
||||
before_remove: contrib/packager.io/preinstall.sh
|
||||
before:
|
||||
- contrib/packager.io/before.sh
|
||||
dependencies:
|
||||
- curl
|
||||
- "python3.9 | python3.10 | python3.11 | python3.12 | python3.13 | python3.14"
|
||||
- "python3.9-venv | python3.10-venv | python3.11-venv | python3.12-venv | python3.13-venv | python3.14-venv"
|
||||
- "python3.9-dev | python3.10-dev | python3.11-dev | python3.12-dev | python3.13-dev | python3.14-dev"
|
||||
- "python3.9 | python3.10 | python3.11"
|
||||
- "python3.9-venv | python3.10-venv | python3.11-venv"
|
||||
- "python3.9-dev | python3.10-dev | python3.11-dev"
|
||||
- python3-pip
|
||||
- python3-cffi
|
||||
- python3-brotli
|
||||
@@ -33,10 +32,7 @@ dependencies:
|
||||
- gettext
|
||||
- nginx
|
||||
- jq
|
||||
- "libffi7 | libffi8"
|
||||
- libffi7
|
||||
targets:
|
||||
ubuntu-20.04: true
|
||||
ubuntu-22.04: true
|
||||
ubuntu-24.04: true
|
||||
debian-11: true
|
||||
debian-12: true
|
||||
|
||||
@@ -10,77 +10,84 @@ exclude: |
|
||||
)$
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
exclude: mkdocs.yml
|
||||
- id: mixed-line-ending
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.13
|
||||
rev: v0.4.1
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
args: [--preview]
|
||||
- id: ruff
|
||||
args: [
|
||||
--fix,
|
||||
# --unsafe-fixes,
|
||||
--preview
|
||||
]
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
rev: 0.7.12
|
||||
rev: 0.1.35
|
||||
hooks:
|
||||
- id: pip-compile
|
||||
name: pip-compile requirements-dev.in
|
||||
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --no-strip-extras, --generate-hashes]
|
||||
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --python-version=3.9, --no-strip-extras, --generate-hashes]
|
||||
files: src/backend/requirements-dev\.(in|txt)$
|
||||
- id: pip-compile
|
||||
name: pip-compile requirements.txt
|
||||
args: [src/backend/requirements.in, -o, src/backend/requirements.txt, --no-strip-extras, --generate-hashes]
|
||||
args: [src/backend/requirements.in, -o, src/backend/requirements.txt,--python-version=3.9, --no-strip-extras,--generate-hashes]
|
||||
files: src/backend/requirements\.(in|txt)$
|
||||
- id: pip-compile
|
||||
name: pip-compile requirements.txt
|
||||
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt, --no-strip-extras, --generate-hashes, -b, src/backend/requirements.txt]
|
||||
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt,--python-version=3.9, --no-strip-extras, --generate-hashes]
|
||||
files: contrib/dev_reqs/requirements\.(in|txt)$
|
||||
- id: pip-compile
|
||||
name: pip-compile requirements.txt
|
||||
args: [docs/requirements.in, -o, docs/requirements.txt, --no-strip-extras, --generate-hashes, -b, src/backend/requirements.txt]
|
||||
args: [docs/requirements.in, -o, docs/requirements.txt,--python-version=3.9, --no-strip-extras, --generate-hashes]
|
||||
files: docs/requirements\.(in|txt)$
|
||||
- id: pip-compile
|
||||
name: pip-compile requirements.txt
|
||||
args: [contrib/container/requirements.in, -o, contrib/container/requirements.txt, --python-version=3.11, --no-strip-extras, --generate-hashes, -b, src/backend/requirements.txt]
|
||||
args: [contrib/container/requirements.in, -o, contrib/container/requirements.txt,--python-version=3.11, --no-strip-extras, --generate-hashes]
|
||||
files: contrib/container/requirements\.(in|txt)$
|
||||
- repo: https://github.com/Riverside-Healthcare/djLint
|
||||
rev: v1.36.4
|
||||
rev: v1.34.1
|
||||
hooks:
|
||||
- id: djlint-django
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.4.1
|
||||
rev: v2.2.6
|
||||
hooks:
|
||||
- id: codespell
|
||||
additional_dependencies:
|
||||
- tomli
|
||||
exclude: >
|
||||
(?x)^(
|
||||
docs/docs/stylesheets/.*|
|
||||
docs/docs/javascripts/.*|
|
||||
docs/docs/webfonts/.* |
|
||||
src/frontend/src/locales/.* |
|
||||
pyproject.toml |
|
||||
src/frontend/vite.config.ts |
|
||||
)$
|
||||
- repo: https://github.com/biomejs/pre-commit
|
||||
rev: v2.0.0-beta.5
|
||||
hooks:
|
||||
- id: biome-check
|
||||
additional_dependencies: ["@biomejs/biome@1.9.4"]
|
||||
files: ^src/frontend/.*\.(js|ts|tsx)$
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: "v4.0.0-alpha.8"
|
||||
hooks:
|
||||
- id: prettier
|
||||
files: ^src/frontend/.*\.(js|jsx|ts|tsx)$
|
||||
additional_dependencies:
|
||||
- "prettier@^2.4.1"
|
||||
- "@trivago/prettier-plugin-sort-imports"
|
||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
||||
rev: "v9.1.0"
|
||||
hooks:
|
||||
- id: eslint
|
||||
additional_dependencies:
|
||||
- eslint@^8.41.0
|
||||
- eslint-config-google@^0.14.0
|
||||
- eslint-plugin-react@6.10.3
|
||||
- babel-eslint@6.1.2
|
||||
- "@typescript-eslint/eslint-plugin@latest"
|
||||
- "@typescript-eslint/parser"
|
||||
files: ^src/frontend/.*\.(js|jsx|ts|tsx)$
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.27.2
|
||||
rev: v8.18.2
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
language_version: 1.23.6
|
||||
#- repo: https://github.com/jumanjihouse/pre-commit-hooks
|
||||
# rev: 3.0.0
|
||||
# hooks:
|
||||
|
||||
5
.vscode/extensions.json
vendored
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"biomejs.biome"
|
||||
]
|
||||
}
|
||||
49
.vscode/launch.json
vendored
@@ -6,60 +6,19 @@
|
||||
"configurations": [
|
||||
{
|
||||
"name": "InvenTree Server",
|
||||
"type": "debugpy",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
|
||||
"args": [
|
||||
"runserver",
|
||||
// "0.0.0.0:8000", // expose server in network (useful for testing with mobile app)
|
||||
// "--noreload" // disable auto-reload
|
||||
],
|
||||
"django": true,
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "InvenTree Server - Tests",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
|
||||
"args": [
|
||||
"test",
|
||||
// "part.test_api.PartCategoryAPITest", // run only a specific test
|
||||
],
|
||||
"args": ["runserver"],
|
||||
"django": true,
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "InvenTree Server - 3rd party",
|
||||
"type": "debugpy",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
|
||||
"args": [
|
||||
"runserver"
|
||||
],
|
||||
"django": true,
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": "InvenTree invoke schema",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/.venv/lib/python3.9/site-packages/invoke/__main__.py",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": [
|
||||
"dev.schema","--ignore-warnings"
|
||||
],
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": "schema generation",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/src/backend/InvenTree/manage.py",
|
||||
"args": [
|
||||
"schema",
|
||||
"--file","src/frontend/schema.yml"
|
||||
],
|
||||
"args": ["runserver"],
|
||||
"django": true,
|
||||
"justMyCode": false
|
||||
},
|
||||
|
||||
8
.vscode/settings.json
vendored
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"quickfix.biome": "explicit"
|
||||
}
|
||||
}
|
||||
20
.vscode/tasks.json
vendored
@@ -9,61 +9,61 @@
|
||||
{
|
||||
"label": "worker",
|
||||
"type": "shell",
|
||||
"command": "invoke worker",
|
||||
"command": "inv worker",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "clean-settings",
|
||||
"type": "shell",
|
||||
"command": "invoke int.clean-settings",
|
||||
"command": "inv clean-settings",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "delete-data",
|
||||
"type": "shell",
|
||||
"command": "invoke dev.delete-data",
|
||||
"command": "inv delete-data",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "migrate",
|
||||
"type": "shell",
|
||||
"command": "invoke migrate",
|
||||
"command": "inv migrate",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "server",
|
||||
"type": "shell",
|
||||
"command": "invoke dev.server",
|
||||
"command": "inv server",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "setup-dev",
|
||||
"type": "shell",
|
||||
"command": "invoke dev.setup-dev",
|
||||
"command": "inv setup-dev",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "setup-test",
|
||||
"type": "shell",
|
||||
"command": "invoke dev.setup-test -i --path dev/inventree-demo-dataset",
|
||||
"command": "inv setup-test -i --path dev/inventree-demo-dataset",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "superuser",
|
||||
"type": "shell",
|
||||
"command": "invoke superuser",
|
||||
"command": "inv superuser",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"type": "shell",
|
||||
"command": "invoke dev.test",
|
||||
"command": "inv test",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
{
|
||||
"label": "update",
|
||||
"type": "shell",
|
||||
"command": "invoke update",
|
||||
"command": "inv update",
|
||||
"problemMatcher": [],
|
||||
},
|
||||
]
|
||||
|
||||
43
CHANGELOG.md
@@ -1,43 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file (starting with 1.0.0).
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 1.1.0 - 2025-11-02
|
||||
|
||||
### Added
|
||||
|
||||
- Added `order_queryset` report helper function in [#10439](https://github.com/inventree/InvenTree/pull/10439)
|
||||
- Added `SupplierMixin` to import data from suppliers in [#9761](https://github.com/inventree/InvenTree/pull/9761)
|
||||
- Added much more detailed status information for machines to the API endpoint (including backend and frontend changes) in [#10381](https://github.com/inventree/InvenTree/pull/10381)
|
||||
- Added ability to partially complete and partially scrap build outputs in [#10499](https://github.com/inventree/InvenTree/pull/10499)
|
||||
- Added support for Redis ACL user-based authentication in [#10551](https://github.com/inventree/InvenTree/pull/10551)
|
||||
- Expose stock adjustment forms to the UI plugin context in [#10584](https://github.com/inventree/InvenTree/pull/10584)
|
||||
- Allow stock adjustments for "in production" items in [#10600](https://github.com/inventree/InvenTree/pull/10600)
|
||||
- Adds optional shipping address against individual sales order shipments in [#10650](https://github.com/inventree/InvenTree/pull/10650)
|
||||
- Adds UI elements to "check" and "uncheck" sales order shipments in [#10654](https://github.com/inventree/InvenTree/pull/10654)
|
||||
- Allow assigning project codes to order line items in [#10657](https://github.com/inventree/InvenTree/pull/10657)
|
||||
- Added support for webauthn login for the frontend in [#9729](https://github.com/inventree/InvenTree/pull/9729)
|
||||
- Added support for Debian 12, Ubuntu 22.04 and Ubuntu 24.04 in the installer and package in [#10705](https://github.com/inventree/InvenTree/pull/10705)
|
||||
- Support for S3 and SFTP storage backends for media and static files ([#10140](https://github.com/inventree/InvenTree/pull/10140))
|
||||
- Adds hooks for custom UI spotlight actions in [#10720](https://github.com/inventree/InvenTree/pull/10720)
|
||||
- Support uploading attachments against SupplierPart in [#10724](https://github.com/inventree/InvenTree/pull/10724)
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed site URL check to allow protocol mismatches if `INVENTREE_SITE_LAX_PROTOCOL` is set to `True` (default) in [#10454](https://github.com/inventree/InvenTree/pull/10454)
|
||||
- Changed call signature of `get_global_setting` to use `environment_key` instead of `enviroment_key` in [#10557](https://github.com/inventree/InvenTree/pull/10557)
|
||||
|
||||
|
||||
## 1.0.0 - 2025-09-15
|
||||
|
||||
The first "stable" release following semver but not extensively other than the previous releases. The use of 1.0 indicates the stability that users already expect from InvenTree.
|
||||
|
||||
An overarching theme of this release is the complete switch to a new UI framework and paradigm (PUI). The old templating based UI (CUI) is now removed. This makes major improvements in the security and portability of InvenTree possible.
|
||||
|
||||
Our blog holds [a few articles](https://inventree.org/blog/2024/09/23/ui-roadmap) on the topic. This journey started in [March 2022](https://github.com/inventree/InvenTree/issues/2789) and was announced [in 2023](https://inventree.org/blog/2023/08/28/react).
|
||||
|
||||
|
||||
Specific entries to the changelog will be kept for all stable channel minor releases, for changes in 1.0 please refer to the [blog posts](https://inventree.org/blog/2025/09/15/1.0.0) and the [milestone](https://github.com/inventree/InvenTree/milestone/17)
|
||||
@@ -1,128 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
support AT inventree DOR org.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -39,7 +39,7 @@ InvenTree/
|
||||
│ │ ├─ tsconfig.json # Settings for frontend compilation
|
||||
├─ .pkgr.yml # Build definition for Debian/Ubuntu packages
|
||||
├─ .pre-commit-config.yaml # Code formatter/linter configuration
|
||||
├─ CONTRIBUTING.md # Contribution guidelines and overview
|
||||
├─ CONTRIBUTING.md # Contirbution guidelines and overview
|
||||
├─ Procfile # Process definition for Debian/Ubuntu packages
|
||||
├─ README.md # General project information and overview
|
||||
├─ runtime.txt # Python runtime settings for Debian/Ubuntu packages build
|
||||
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 - InvenTree Developers
|
||||
Copyright (c) 2017-2022 InvenTree
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
64
README.md
@@ -4,15 +4,13 @@
|
||||
<p>Open Source Inventory Management System </p>
|
||||
|
||||
<!-- Badges -->
|
||||
[](https://opensource.org/license/MIT)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||

|
||||
[](https://inventree.readthedocs.io/en/latest/?badge=latest)
|
||||

|
||||
[](https://app.netlify.com/sites/inventree/deploys)
|
||||
[](https://dev.azure.com/InvenTree/InvenTree%20test%20statistics/_build/latest?definitionId=3&branchName=testing)
|
||||
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/7179)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/inventree/InvenTree)
|
||||
[](https://app.netlify.com/sites/inventree/deploys)
|
||||
[](https://sonarcloud.io/summary/new_code?id=inventree_InvenTree)
|
||||
|
||||
[](https://codecov.io/gh/inventree/InvenTree)
|
||||
@@ -20,10 +18,10 @@
|
||||

|
||||
[](https://hub.docker.com/r/inventree/inventree)
|
||||
|
||||
[](https://github.com/inventree/InvenTree/)
|
||||

|
||||
[](https://twitter.com/inventreedb)
|
||||
[](https://www.reddit.com/r/InvenTree/)
|
||||
[](https://chaos.social/@InvenTree)
|
||||
|
||||
|
||||
<h4>
|
||||
<a href="https://demo.inventree.org/">View Demo</a>
|
||||
@@ -53,10 +51,10 @@ Want to see what we are working on? Check out the [roadmap tag](https://github.c
|
||||
|
||||
InvenTree is designed to be **extensible**, and provides multiple options for **integration** with external applications or addition of custom plugins:
|
||||
|
||||
* [InvenTree API](https://docs.inventree.org/en/latest/api/)
|
||||
* [Python module](https://docs.inventree.org/en/latest/api/python/)
|
||||
* [Plugin interface](https://docs.inventree.org/en/latest/plugins/)
|
||||
* [Third party tools](https://docs.inventree.org/en/latest/plugins/integrate/)
|
||||
* [InvenTree API](https://docs.inventree.org/en/latest/api/api/)
|
||||
* [Python module](https://docs.inventree.org/en/latest/api/python/python/)
|
||||
* [Plugin interface](https://docs.inventree.org/en/latest/extend/plugins)
|
||||
* [Third party tools](https://docs.inventree.org/en/latest/extend/integrate)
|
||||
|
||||
<!-- TechStack -->
|
||||
### :space_invader: Tech Stack
|
||||
@@ -68,7 +66,7 @@ InvenTree is designed to be **extensible**, and provides multiple options for **
|
||||
<li><a href="https://www.djangoproject.com/">Django</a></li>
|
||||
<li><a href="https://www.django-rest-framework.org/">DRF</a></li>
|
||||
<li><a href="https://django-q.readthedocs.io/">Django Q</a></li>
|
||||
<li><a href="https://docs.allauth.org/">Django-Allauth</a></li>
|
||||
<li><a href="https://django-allauth.readthedocs.io/">Django-Allauth</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
@@ -85,14 +83,9 @@ InvenTree is designed to be **extensible**, and provides multiple options for **
|
||||
<details>
|
||||
<summary>Client</summary>
|
||||
<ul>
|
||||
<li><a href="https://react.dev/">React</a></li>
|
||||
<li><a href="https://lingui.dev/">Lingui</a></li>
|
||||
<li><a href="https://reactrouter.com/">React Router</a></li>
|
||||
<li><a href="https://tanstack.com/query/">TanStack Query</a></li>
|
||||
<li><a href="https://github.com/pmndrs/zustand">Zustand</a></li>
|
||||
<li><a href="https://mantine.dev/">Mantine</a></li>
|
||||
<li><a href="https://icflorescu.github.io/mantine-datatable/">Mantine Data Table</a></li>
|
||||
<li><a href="https://codemirror.net/">CodeMirror</a></li>
|
||||
<li><a href="https://getbootstrap.com/">Bootstrap</a></li>
|
||||
<li><a href="https://jquery.com/">jQuery</a></li>
|
||||
<li><a href="https://bootstrap-table.com/">Bootstrap-Table</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
@@ -102,7 +95,7 @@ InvenTree is designed to be **extensible**, and provides multiple options for **
|
||||
<li><a href="https://hub.docker.com/r/inventree/inventree">Docker</a></li>
|
||||
<li><a href="https://crowdin.com/project/inventree">Crowdin</a></li>
|
||||
<li><a href="https://app.codecov.io/gh/inventree/InvenTree">Codecov</a></li>
|
||||
<li><a href="https://sonarcloud.io/project/overview?id=inventree_InvenTree">SonarCloud</a></li>
|
||||
<li><a href="https://app.deepsource.com/gh/inventree/InvenTree">DeepSource</a></li>
|
||||
<li><a href="https://packager.io/gh/inventree/InvenTree">Packager.io</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
@@ -130,7 +123,7 @@ Refer to the [getting started guide](https://docs.inventree.org/en/latest/start/
|
||||
<!-- Mobile App -->
|
||||
## :iphone: Mobile App
|
||||
|
||||
InvenTree is supported by a [companion mobile app](https://docs.inventree.org/en/latest/app/) which allows users access to stock control information and functionality.
|
||||
InvenTree is supported by a [companion mobile app](https://docs.inventree.org/en/latest/app/app/) which allows users access to stock control information and functionality.
|
||||
|
||||
<div align="center"><h4>
|
||||
<a href="https://play.google.com/store/apps/details?id=inventree.inventree_app">Android Play Store</a>
|
||||
@@ -138,17 +131,10 @@ InvenTree is supported by a [companion mobile app](https://docs.inventree.org/en
|
||||
<a href="https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone">Apple App Store</a>
|
||||
</h4></div>
|
||||
|
||||
<!-- Security -->
|
||||
## :lock: Code of Conduct & Security Policy
|
||||
|
||||
The InvenTree project team is committed to providing a safe and welcoming environment for all users. Please read our [Code of Conduct](CODE_OF_CONDUCT.md) for more information.
|
||||
|
||||
InvenTree is following industry best practices for security. Our security policy is included [in this repo](SECURITY.md). We provide dedicated security pages on [our documentation site](https://docs.inventree.org/en/latest/security/).
|
||||
|
||||
<!-- Contributing -->
|
||||
## :wave: Contributing
|
||||
|
||||
Contributions are welcomed and encouraged. Please help to make this project even better! Refer to the [contribution page](https://docs.inventree.org/en/latest/develop/contributing/).
|
||||
Contributions are welcomed and encouraged. Please help to make this project even better! Refer to the [contribution page](CONTRIBUTING.md).
|
||||
|
||||
<!-- Translation -->
|
||||
## :scroll: Translation
|
||||
@@ -163,8 +149,11 @@ If you use InvenTree and find it to be useful, please consider [sponsoring the p
|
||||
<!-- Acknowledgments -->
|
||||
## :gem: Acknowledgements
|
||||
|
||||
We want to acknowledge [PartKeepr](https://github.com/partkeepr/PartKeepr) as a valuable predecessor and inspiration.
|
||||
Find a full list of used third-party libraries in the license information dialog of your instance.
|
||||
We would like to acknowledge a few special projects:
|
||||
- [PartKeepr](https://github.com/partkeepr/PartKeepr) as a valuable predecessor and inspiration
|
||||
- [Readme Template](https://github.com/Louis3797/awesome-readme-template) for the template of this page
|
||||
|
||||
Find a full list of used third-party libraries in [our documentation](https://docs.inventree.org/en/latest/credits/).
|
||||
|
||||
## :heart: Support
|
||||
|
||||
@@ -180,26 +169,17 @@ Find a full list of used third-party libraries in the license information dialog
|
||||
<a href="https://github.com/PricelessToolkit"><img src="https://github.com/PricelessToolkit.png" width="60px" alt="" /></a>
|
||||
<a href="https://github.com/cabottech"><img src="https://github.com/cabottech.png" width="60px" alt="Cabot Technologies" /></a>
|
||||
<a href="https://github.com/markus-k"><img src="https://github.com/markus-k.png" width="60px" alt="Markus Kasten" /></a>
|
||||
<a href="https://github.com/jefffhaynes"><img src="https://github.com/jefffhaynes.png" width="60px" alt="Jeff Haynes" /></a>
|
||||
<a href="https://github.com/dnviti"><img src="https://github.com/dnviti.png" width="60px" alt="Daniele Viti" /></a>
|
||||
<a href="https://github.com/Islendur"><img src="https://github.com/Islendur.png" width="60px" alt="Islendur" /></a>
|
||||
<a href="https://github.com/Gibeon-NL"><img src="https://github.com/Gibeon-NL.png" width="60px" alt="Gibeon-NL" /></a>
|
||||
<a href="https://github.com/Motrac-Research-Engineering"><img src="https://github.com/Motrac-Research-Engineering.png" width="60px" alt="Motrac Research" /></a>
|
||||
<a href="https://github.com/trytuna"><img src="https://github.com/trytuna.png" width="60px" alt="Timo Scrappe" /></a>
|
||||
<a href="https://github.com/ATLAS2246"><img src="https://github.com/ATLAS2246.png" width="60px" alt="ATLAS2246" /></a>
|
||||
<a href="https://github.com/Kedarius"><img src="https://github.com/Kedarius.png" width="60px" alt="Radek Hladik" /></a>
|
||||
|
||||
<a href="https://github.com/jefffhaynes"><img src="https://github.com/jefffhaynes.png" width="60px" alt="Jess Haynes" /></a>
|
||||
</p>
|
||||
|
||||
<p>With ongoing resources provided by:</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://depot.dev?utm_source=inventree"><img src="https://depot.dev/badges/built-with-depot.svg" alt="Built with Depot" /></a>
|
||||
<a href="https://inventree.org/digitalocean">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px" alt="Servers by Digital Ocean">
|
||||
</a>
|
||||
<a href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-bg.svg" alt="Deploys by Netlify" /> </a>
|
||||
<a href="https://crowdin.com"> <img src="https://crowdin.com/images/crowdin-logo.svg" alt="Translation by Crowdin" /> </a> <br>
|
||||
<a href="https://crowdin.com"> <img src="https://crowdin.com/images/crowdin-logo.svg" alt="Translation by Crowdin" /> </a>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
23
RELEASE.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## Release Checklist
|
||||
|
||||
Checklist of steps to perform at each code release
|
||||
|
||||
### Update Version String
|
||||
|
||||
Update `INVENTREE_SW_VERSION` in [version.py](https://github.com/inventree/InvenTree/blob/master/src/backend/InvenTree/InvenTree/version.py)
|
||||
|
||||
### Increment API Version
|
||||
|
||||
If the API has changed, ensure that the API version number is incremented.
|
||||
|
||||
### Translation Files
|
||||
|
||||
Merge the crowdin translation updates into master branch
|
||||
|
||||
### Python Library Release
|
||||
|
||||
Create new release for the [InvenTree python library](https://github.com/inventree/inventree-python)
|
||||
|
||||
## App Release
|
||||
|
||||
Create new versioned release for the InvenTree mobile app.
|
||||
10
SECURITY.md
@@ -1,9 +1,7 @@
|
||||
# Security Policy
|
||||
|
||||
The InvenTree team take all security vulnerabilities seriously. Thank you for improving the security of our open source software.
|
||||
|
||||
We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
|
||||
The general project security policies and processes are documented in [our documentation](https://docs.inventree.org/en/stable/security/).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
@@ -13,13 +11,7 @@ Please report security vulnerabilities by emailing the InvenTree team at:
|
||||
security@inventree.org
|
||||
```
|
||||
|
||||
Someone from the InvenTree development team will acknowledge your email as soon as possible (normally within a week), and indicate the next steps in handling your security report.
|
||||
Someone from the InvenTree development team will acknowledge your email as soon as possible, and indicate the next steps in handling your security report.
|
||||
|
||||
|
||||
The team will endeavour to keep you informed of the progress towards a fix for the issue, and subsequent release to the stable and development code branches. Where possible, the issue will be resolved within 90 days of reporting.
|
||||
|
||||
### Public Disclosure
|
||||
|
||||
Using GitHub's security advisory system, we will publish a public disclosure of the issue once it has been acknowledged, reproduced and resolved.
|
||||
We support assigning CVEs to security issues where appropriate.
|
||||
The project can be identified by the CPE code ``cpe:2.3:a:inventree_project:inventree:``.
|
||||
|
||||
40
biome.json
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "single",
|
||||
"jsxQuoteStyle": "single",
|
||||
"trailingCommas": "none",
|
||||
"indentStyle": "space"
|
||||
}
|
||||
},
|
||||
"linter": {
|
||||
"rules": {
|
||||
"suspicious" : {
|
||||
"noExplicitAny": "off",
|
||||
"noDoubleEquals": "off",
|
||||
"noArrayIndexKey": "off",
|
||||
"useDefaultSwitchClauseLast": "off"
|
||||
},
|
||||
"style": {
|
||||
"noUselessElse": "off",
|
||||
"noNonNullAssertion": "off",
|
||||
"noParameterAssign": "off"
|
||||
}, "correctness":{
|
||||
"useExhaustiveDependencies": "off",
|
||||
"useJsxKeyInIterable": "off",
|
||||
"noUnsafeOptionalChaining": "off",
|
||||
"noSwitchDeclarations": "off",
|
||||
"noUnusedImports":"error"
|
||||
}, "complexity": {
|
||||
"noBannedTypes": "off",
|
||||
"noExtraBooleanCast": "off",
|
||||
"noForEach": "off",
|
||||
"noUselessSwitchCase": "off",
|
||||
"useLiteralKeys":"off"
|
||||
}, "performance": {
|
||||
"noDelete":"off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
codecov.yml
@@ -2,8 +2,7 @@ coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 85%
|
||||
patch: off
|
||||
target: 82%
|
||||
|
||||
github_checks:
|
||||
annotations: true
|
||||
@@ -22,62 +21,8 @@ flag_management:
|
||||
statuses:
|
||||
- type: project
|
||||
target: 40%
|
||||
- name: web
|
||||
- name: pui
|
||||
carryforward: true
|
||||
statuses:
|
||||
- type: project
|
||||
target: 45%
|
||||
|
||||
component_management:
|
||||
default_rules:
|
||||
statuses:
|
||||
- type: project
|
||||
target: auto
|
||||
branches:
|
||||
- "!main"
|
||||
individual_components:
|
||||
- component_id: backend-apps
|
||||
name: Backend Apps
|
||||
paths:
|
||||
- src/backend/InvenTree/build/**
|
||||
- src/backend/InvenTree/company/**
|
||||
- src/backend/InvenTree/data_exporter/**
|
||||
- src/backend/InvenTree/importer/**
|
||||
- src/backend/InvenTree/machine/**
|
||||
- src/backend/InvenTree/order/**
|
||||
- src/backend/InvenTree/part/**
|
||||
- src/backend/InvenTree/plugin/**
|
||||
- src/backend/InvenTree/report/**
|
||||
- src/backend/InvenTree/stock/**
|
||||
- src/backend/InvenTree/users/**
|
||||
- src/backend/InvenTree/web/**
|
||||
statuses:
|
||||
- type: project
|
||||
target: 90%
|
||||
- component_id: backend-general
|
||||
name: Backend General
|
||||
paths:
|
||||
- src/backend/InvenTree/generic/**
|
||||
- src/backend/InvenTree/common/**
|
||||
statuses:
|
||||
- type: project
|
||||
target: 92% # 95%
|
||||
- type: patch
|
||||
target: 95%
|
||||
- component_id: web
|
||||
name: Frontend
|
||||
paths:
|
||||
- src/frontend/**
|
||||
statuses:
|
||||
- type: project
|
||||
target: 68% # 90%
|
||||
- type: patch
|
||||
target: 80%
|
||||
comment:
|
||||
require_bundle_changes: True
|
||||
bundle_change_threshold: "1Kb"
|
||||
layout: "header, diff, flags, components"
|
||||
|
||||
bundle_analysis:
|
||||
warning_threshold: "5%"
|
||||
status: "informational"
|
||||
|
||||
1
config/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
*
|
||||
@@ -1 +0,0 @@
|
||||
This folder is recommended for configuration values and excluded from change tracking in git
|
||||
@@ -1,61 +1,49 @@
|
||||
# InvenTree environment variables for docker compose deployment
|
||||
# For a full list of the available configuration options, refer to the InvenTree documentation:
|
||||
# https://docs.inventree.org/en/stable/start/config/
|
||||
|
||||
# Specify the name of the docker-compose project
|
||||
COMPOSE_PROJECT_NAME=inventree
|
||||
|
||||
# InvenTree version tag (e.g. 'stable' / 'latest' / 'x.x.x')
|
||||
INVENTREE_TAG=stable
|
||||
|
||||
# InvenTree server URL - update this to match your server URL
|
||||
INVENTREE_SITE_URL="http://inventree.localhost"
|
||||
#INVENTREE_SITE_URL="http://192.168.1.2" # You can specify a local IP address here
|
||||
#INVENTREE_SITE_URL="https://inventree.my-domain.com" # Or a public domain name (which you control)
|
||||
|
||||
# InvenTree proxy forwarding settings
|
||||
INVENTREE_USE_X_FORWARDED_HOST=True
|
||||
INVENTREE_USE_X_FORWARDED_PORT=True
|
||||
INVENTREE_USE_X_FORWARDED_PROTO=True
|
||||
|
||||
# Specify the location of the external data volume
|
||||
# By default, placed in local directory 'inventree-data'
|
||||
INVENTREE_EXT_VOLUME=./inventree-data
|
||||
|
||||
# Ensure debug is false for a production setup
|
||||
INVENTREE_DEBUG=False
|
||||
INVENTREE_LOG_LEVEL=WARNING
|
||||
|
||||
# Enable custom plugins?
|
||||
INVENTREE_PLUGINS_ENABLED=True
|
||||
|
||||
# Run database migrations automatically?
|
||||
# Note: This does not negate the need to run "invoke update"
|
||||
INVENTREE_AUTO_UPDATE=True
|
||||
|
||||
# InvenTree superuser account details
|
||||
# Un-comment (and complete) these lines to auto-create an admin account
|
||||
# InvenTree admin account details
|
||||
# Un-comment (and complete) these lines to auto-create an admin acount
|
||||
#INVENTREE_ADMIN_USER=
|
||||
#INVENTREE_ADMIN_PASSWORD=
|
||||
#INVENTREE_ADMIN_EMAIL=
|
||||
|
||||
# Database configuration options
|
||||
# DO NOT CHANGE THESE SETTINGS (unless you really know what you are doing)
|
||||
INVENTREE_DB_ENGINE=postgresql
|
||||
INVENTREE_DB_NAME=inventree
|
||||
INVENTREE_DB_HOST=inventree-db
|
||||
INVENTREE_DB_PORT=5432
|
||||
|
||||
# Database credentials - These should be changed from the default values!
|
||||
# Note: These are *NOT* the InvenTree server login credentials,
|
||||
# they are the credentials for the PostgreSQL database
|
||||
INVENTREE_DB_USER=pguser
|
||||
INVENTREE_DB_PASSWORD=pgpassword
|
||||
|
||||
# Redis cache setup
|
||||
# Refer to the documentation for other cache options
|
||||
INVENTREE_CACHE_ENABLED=True
|
||||
INVENTREE_CACHE_HOST=inventree-cache
|
||||
INVENTREE_CACHE_PORT=6379
|
||||
# Redis cache setup (disabled by default)
|
||||
# Un-comment the following lines to enable Redis cache
|
||||
# Note that you will also have to run docker-compose with the --profile redis command
|
||||
# Refer to settings.py for other cache options
|
||||
#INVENTREE_CACHE_HOST=inventree-cache
|
||||
#INVENTREE_CACHE_PORT=6379
|
||||
|
||||
# Options for gunicorn server
|
||||
INVENTREE_GUNICORN_TIMEOUT=90
|
||||
|
||||
# Enable custom plugins?
|
||||
INVENTREE_PLUGINS_ENABLED=True
|
||||
|
||||
# Run migrations automatically?
|
||||
INVENTREE_AUTO_UPDATE=True
|
||||
|
||||
# Image tag that should be used
|
||||
INVENTREE_TAG=stable
|
||||
|
||||
# Site URL - update this to match your host
|
||||
INVENTREE_SITE_URL="http://inventree.localhost"
|
||||
|
||||
COMPOSE_PROJECT_NAME=inventree
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
# Example Caddyfile for InvenTree
|
||||
# Example Caddyfile for Inventree
|
||||
# The following environment variables may be used:
|
||||
# - INVENTREE_SITE_URL: The upstream URL of the InvenTree site (default: inventree.localhost)
|
||||
# - INVENTREE_SERVER: The internal URL of the InvenTree container (default: http://inventree-server:8000)
|
||||
# - INVENTREE_SITE_URL: The upstream URL of the Inventree site (default: inventree.localhost)
|
||||
# - INVENTREE_SERVER: The internal URL of the Inventree container (default: http://inventree-server:8000)
|
||||
#
|
||||
# Note that while this file is a good starting point, it may need to be modified to suit your specific requirements
|
||||
#
|
||||
# Ref to the Caddyfile documentation: https://caddyserver.com/docs/caddyfile
|
||||
|
||||
|
||||
# Logging configuration for Caddy
|
||||
(log_common) {
|
||||
log {
|
||||
output file /var/log/caddy/{args[0]}.access.log
|
||||
}
|
||||
}
|
||||
|
||||
# CORS headers control (used for static and media files)
|
||||
(cors-headers) {
|
||||
header Allow GET,HEAD,OPTIONS
|
||||
header Access-Control-Allow-Origin *
|
||||
@@ -29,10 +25,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
# The default server address is configured in the .env file
|
||||
# If not specified, the proxy listens for all http/https traffic
|
||||
# If you need to listen on multiple addresses, or use a different port, you can modify this section directly
|
||||
{$INVENTREE_SITE_URL:"http://, https://"} {
|
||||
# Change the host to your domain (this will serve at inventree.localhost)
|
||||
{$INVENTREE_SITE_URL:inventree.localhost} {
|
||||
import log_common inventree
|
||||
|
||||
encode gzip
|
||||
@@ -41,7 +35,6 @@
|
||||
max_size 100MB
|
||||
}
|
||||
|
||||
# Handle static request files
|
||||
handle_path /static/* {
|
||||
import cors-headers static
|
||||
|
||||
@@ -49,29 +42,18 @@
|
||||
file_server
|
||||
}
|
||||
|
||||
# Handle media request files
|
||||
handle_path /media/* {
|
||||
import cors-headers media
|
||||
|
||||
root * /var/www/media
|
||||
file_server
|
||||
|
||||
# Force download of media files (for security)
|
||||
# Comment out this line if you do not want to force download
|
||||
header Content-Disposition attachment
|
||||
|
||||
# Authentication is handled by the forward_auth directive
|
||||
# This is required to ensure that media files are only accessible to authenticated users
|
||||
forward_auth {$INVENTREE_SERVER:"http://inventree-server:8000"} {
|
||||
uri /auth/
|
||||
}
|
||||
}
|
||||
|
||||
# All other requests are proxied to the InvenTree server
|
||||
reverse_proxy {$INVENTREE_SERVER:"http://inventree-server:8000"} {
|
||||
|
||||
# If you are running behind another proxy, you may need to specify 'trusted_proxies'
|
||||
# Ref: https://caddyserver.com/docs/json/apps/http/servers/trusted_proxies/
|
||||
# trusted_proxies ...
|
||||
}
|
||||
reverse_proxy {$INVENTREE_SERVER:"http://inventree-server:8000"}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
# - Runs InvenTree web server under django development server
|
||||
# - Monitors source files for any changes, and live-reloads server
|
||||
|
||||
FROM python:3.11-slim-trixie@sha256:1d6131b5d479888b43200645e03a78443c7157efbdb730e6b48129740727c312 AS inventree_base
|
||||
ARG base_image=python:3.11-alpine3.18
|
||||
FROM ${base_image} AS inventree_base
|
||||
|
||||
# Build arguments for this image
|
||||
ARG commit_tag=""
|
||||
@@ -18,9 +19,9 @@ ARG commit_date=""
|
||||
|
||||
ARG data_dir="data"
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
ENV INVOKE_RUN_SHELL="/bin/bash"
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK 1
|
||||
ENV INVOKE_RUN_SHELL="/bin/ash"
|
||||
|
||||
ENV INVENTREE_DOCKER="true"
|
||||
|
||||
@@ -37,7 +38,6 @@ ENV INVENTREE_BACKEND_DIR="${INVENTREE_HOME}/src/backend"
|
||||
# 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_OIDC_PRIVATE_KEY_FILE="${INVENTREE_DATA_DIR}/oidc.pem"
|
||||
ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DATA_DIR}/plugins.txt"
|
||||
|
||||
# Worker configuration (can be altered by user)
|
||||
@@ -48,84 +48,67 @@ ENV INVENTREE_BACKGROUND_WORKERS="4"
|
||||
ENV INVENTREE_WEB_ADDR=0.0.0.0
|
||||
ENV INVENTREE_WEB_PORT=8000
|
||||
|
||||
LABEL org.opencontainers.image.vendor="inventree" \
|
||||
org.opencontainers.image.title="InvenTree backend server" \
|
||||
org.opencontainers.image.description="InvenTree is the open-source inventory management system" \
|
||||
org.opencontainers.image.url="https://inventree.org" \
|
||||
org.opencontainers.image.documentation="https://docs.inventree.org" \
|
||||
org.opencontainers.image.source="https://github.com/inventree/InvenTree" \
|
||||
org.opencontainers.image.revision=${commit_hash} \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.version=${commit_tag}
|
||||
LABEL org.label-schema.schema-version="1.0" \
|
||||
org.label-schema.build-date=${DATE} \
|
||||
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="https://github.com/inventree/InvenTree.git" \
|
||||
org.label-schema.vcs-ref=${commit_tag}
|
||||
|
||||
# Install basic system level packages
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git gettext libldap2 wget curl ssh \
|
||||
# Install required system level packages
|
||||
RUN apk add --no-cache \
|
||||
git gettext py-cryptography \
|
||||
# Image format support
|
||||
libjpeg libwebp zlib \
|
||||
# Weasyprint requirements : https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#alpine-3-12
|
||||
weasyprint libpango-1.0-0 libcairo2 poppler-utils \
|
||||
# Database client libraries
|
||||
postgresql-client mariadb-client \
|
||||
# font support
|
||||
fontconfig fonts-freefont-ttf fonts-terminus fonts-noto-core fonts-noto-cjk \
|
||||
# Cleanup
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Remove heavy python packages installed by weasyprint (that we don't need)
|
||||
RUN rm -rf /usr/lib/python3/dist-packages/numpy \
|
||||
&& rm -rf /usr/lib/python3/dist-packages/scipy \
|
||||
&& rm -rf /usr/lib/python3/dist-packages/sympy
|
||||
py3-pip py3-pillow py3-cffi py3-brotli pango poppler-utils openldap \
|
||||
# Postgres client
|
||||
postgresql13-client \
|
||||
# MySQL / MariaDB client
|
||||
mariadb-client mariadb-connector-c \
|
||||
&& \
|
||||
# fonts
|
||||
apk --update --upgrade --no-cache add fontconfig ttf-freefont font-noto terminus-font && fc-cache -f
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# Fix invoke command path for InvenTree environment check
|
||||
RUN python -m pip install --no-cache-dir -U invoke
|
||||
|
||||
RUN mkdir -p ${INVENTREE_HOME}
|
||||
WORKDIR ${INVENTREE_HOME}
|
||||
|
||||
COPY contrib/container/requirements.txt base_requirements.txt
|
||||
COPY src/backend/requirements.txt ./
|
||||
COPY contrib/container/install_build_packages.sh .
|
||||
RUN chmod +x install_build_packages.sh
|
||||
|
||||
COPY tasks.py \
|
||||
src/backend/requirements.txt \
|
||||
contrib/container/gunicorn.conf.py \
|
||||
contrib/container/init.sh \
|
||||
./
|
||||
# For ARMv7 architecture, add the piwheels repo (for cryptography library)
|
||||
# Otherwise, we have to build from source, which is difficult
|
||||
# Ref: https://github.com/inventree/InvenTree/pull/4598
|
||||
RUN if [ `apk --print-arch` = "armv7" ]; then \
|
||||
printf "[global]\nextra-index-url=https://www.piwheels.org/simple\n" > /etc/pip.conf ; \
|
||||
fi
|
||||
|
||||
COPY tasks.py contrib/container/gunicorn.conf.py contrib/container/init.sh ./
|
||||
RUN chmod +x init.sh
|
||||
|
||||
ENTRYPOINT ["/bin/bash", "./init.sh"]
|
||||
ENTRYPOINT ["/bin/ash", "./init.sh"]
|
||||
|
||||
# Multi-stage build to compile project requirements
|
||||
FROM inventree_base AS builder_stage
|
||||
FROM inventree_base AS prebuild
|
||||
|
||||
# Copy source files
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
RUN ./install_build_packages.sh --no-cache --virtual .build-deps && \
|
||||
pip install --user --require-hashes -r base_requirements.txt --no-cache && \
|
||||
pip install --user --require-hashes -r requirements.txt --no-cache && \
|
||||
apk --purge del .build-deps
|
||||
|
||||
# Frontend builder image:
|
||||
FROM prebuild AS frontend
|
||||
|
||||
RUN apk add --no-cache --update nodejs npm yarn
|
||||
RUN yarn config set network-timeout 600000 -g
|
||||
COPY src ${INVENTREE_HOME}/src
|
||||
COPY tasks.py ${INVENTREE_HOME}/tasks.py
|
||||
|
||||
# Install backend build dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config build-essential \
|
||||
libldap2-dev libsasl2-dev libssl-dev \
|
||||
libmariadb-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Build and install python dependencies
|
||||
RUN pip install --user --require-hashes -r base_requirements.txt --no-cache-dir && \
|
||||
pip install --user --require-hashes -r requirements.txt --no-cache-dir && \
|
||||
pip cache purge && \
|
||||
rm -rf /root/.cache/pip
|
||||
|
||||
# Install frontend build dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
nodejs npm \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN npm install -g n yarn --ignore-scripts && \
|
||||
yarn config set network-timeout 600000 -g
|
||||
RUN bash -c "n lts"
|
||||
RUN cd "${INVENTREE_HOME}" && invoke int.frontend-compile --extract
|
||||
RUN cd ${INVENTREE_HOME} && inv frontend-compile
|
||||
|
||||
# InvenTree production image:
|
||||
# - Copies required files from local directory
|
||||
@@ -138,26 +121,34 @@ ENV INVENTREE_DEBUG=False
|
||||
ENV INVENTREE_COMMIT_HASH="${commit_hash}"
|
||||
ENV INVENTREE_COMMIT_DATE="${commit_date}"
|
||||
|
||||
# use dependencies and compiled wheels from the prebuild image
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
COPY --from=prebuild /root/.local /root/.local
|
||||
|
||||
|
||||
# Copy source code
|
||||
COPY src/backend/InvenTree ${INVENTREE_BACKEND_DIR}/InvenTree
|
||||
COPY src/backend/requirements.txt ${INVENTREE_BACKEND_DIR}/requirements.txt
|
||||
|
||||
# Copy compiled dependencies from prebuild image
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
|
||||
COPY --from=builder_stage ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web
|
||||
COPY --from=builder_stage /root/.local /root/.local
|
||||
COPY --from=frontend ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web ${INVENTREE_BACKEND_DIR}/InvenTree/web/static/web
|
||||
|
||||
# Launch the production server
|
||||
CMD ["sh", "-c", "exec gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ${INVENTREE_BACKEND_DIR}/InvenTree"]
|
||||
CMD gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ${INVENTREE_BACKEND_DIR}/InvenTree
|
||||
|
||||
FROM builder_stage AS dev
|
||||
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
FROM inventree_base AS dev
|
||||
|
||||
# Vite server (for local frontend development)
|
||||
EXPOSE 5173
|
||||
|
||||
# Install packages required for building python packages
|
||||
RUN ./install_build_packages.sh
|
||||
|
||||
RUN pip install --require-hashes -r base_requirements.txt --no-cache
|
||||
|
||||
# Install nodejs / npm / yarn
|
||||
|
||||
RUN apk add --no-cache --update nodejs npm yarn
|
||||
RUN yarn config set network-timeout 600000 -g
|
||||
|
||||
# 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
|
||||
|
||||
@@ -170,7 +161,7 @@ ENV INVENTREE_PY_ENV="${INVENTREE_DATA_DIR}/env"
|
||||
WORKDIR ${INVENTREE_HOME}
|
||||
|
||||
# Entrypoint ensures that we are running in the python virtual environment
|
||||
ENTRYPOINT ["/bin/bash", "./contrib/container/init.sh"]
|
||||
ENTRYPOINT ["/bin/ash", "./contrib/container/init.sh"]
|
||||
|
||||
# Launch the development server
|
||||
CMD ["invoke", "dev.server", "-a", "${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}"]
|
||||
CMD ["invoke", "server", "-a", "${INVENTREE_WEB_ADDR}:${INVENTREE_WEB_PORT}"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
version: "3.8"
|
||||
|
||||
# Docker compose recipe for InvenTree development server
|
||||
# - Runs PostgreSQL as the database backend
|
||||
# - Uses built-in django webserver
|
||||
@@ -18,7 +20,7 @@ services:
|
||||
# Use PostgreSQL as the database backend
|
||||
# Note: This can be changed to a different backend if required
|
||||
inventree-dev-db:
|
||||
image: postgres:17
|
||||
image: postgres:13
|
||||
expose:
|
||||
- 5432/tcp
|
||||
environment:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
version: "3.8"
|
||||
|
||||
# Docker compose recipe for a production-ready InvenTree setup, with the following containers:
|
||||
# - PostgreSQL as the database backend
|
||||
# - gunicorn as the InvenTree web server
|
||||
@@ -32,17 +34,11 @@
|
||||
# INVENTREE_TAG=0.7.5
|
||||
#
|
||||
|
||||
# ----------------------------
|
||||
# Docker compose customization
|
||||
# ----------------------------
|
||||
# If you wish to customize the docker-compose script, you should only do so if you understand the stack!
|
||||
# Do not expect support for customizations that are not part of the standard InvenTree setup!
|
||||
|
||||
services:
|
||||
# Database service
|
||||
# Use PostgreSQL as the database backend
|
||||
inventree-db:
|
||||
image: postgres:17
|
||||
image: postgres:13
|
||||
container_name: inventree-db
|
||||
expose:
|
||||
- ${INVENTREE_DB_PORT:-5432}/tcp
|
||||
@@ -57,9 +53,14 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
# redis acts as database cache manager
|
||||
# only runs under the "redis" profile : https://docs.docker.com/compose/profiles/
|
||||
inventree-cache:
|
||||
image: redis:7-alpine
|
||||
image: redis:7.0
|
||||
container_name: inventree-cache
|
||||
depends_on:
|
||||
- inventree-db
|
||||
profiles:
|
||||
- redis
|
||||
env_file:
|
||||
- .env
|
||||
expose:
|
||||
@@ -77,7 +78,6 @@ services:
|
||||
- 8000
|
||||
depends_on:
|
||||
- inventree-db
|
||||
- inventree-cache
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
@@ -101,7 +101,6 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
# caddy acts as reverse proxy and static file server
|
||||
# You can adjust the ports that the proxy listens on via the .env file
|
||||
# https://hub.docker.com/_/caddy
|
||||
inventree-proxy:
|
||||
container_name: inventree-proxy
|
||||
@@ -110,8 +109,8 @@ services:
|
||||
depends_on:
|
||||
- inventree-server
|
||||
ports:
|
||||
- ${INVENTREE_HTTP_PORT:-80}:80
|
||||
- ${INVENTREE_HTTPS_PORT:-443}:443
|
||||
- ${INVENTREE_WEB_PORT:-80}:80
|
||||
- 443:443
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
@@ -121,3 +120,17 @@ services:
|
||||
- ${INVENTREE_EXT_VOLUME}:/var/log:z
|
||||
- ${INVENTREE_EXT_VOLUME}:/data:z
|
||||
- ${INVENTREE_EXT_VOLUME}:/config:z
|
||||
|
||||
# alternative: run nginx as reverse proxy
|
||||
# inventree-proxy:
|
||||
# container_name: inventree-proxy
|
||||
# image: nginx:stable
|
||||
# restart: always
|
||||
# depends_on:
|
||||
# - inventree-server
|
||||
# ports:
|
||||
# - ${INVENTREE_WEB_PORT:-80}:80
|
||||
# - 443:443
|
||||
# volumes:
|
||||
# - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro,z
|
||||
# - ${INVENTREE_EXT_VOLUME}:/var/www:z
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
# InvenTree environment variables for a development setup
|
||||
# These variables will be used by the docker-compose.yml file
|
||||
|
||||
INVENTREE_SITE_URL=http://localhost:8000
|
||||
|
||||
# Set DEBUG to True for a development setup
|
||||
INVENTREE_DEBUG=True
|
||||
INVENTREE_LOG_LEVEL=WARNING
|
||||
INVENTREE_LOG_LEVEL=INFO
|
||||
INVENTREE_DB_LOGGING=False
|
||||
|
||||
# Database configuration options
|
||||
|
||||
@@ -19,7 +19,7 @@ threads = 4
|
||||
|
||||
|
||||
# Worker timeout (default = 90 seconds)
|
||||
timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', '90')
|
||||
timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', 90)
|
||||
|
||||
# Number of worker processes
|
||||
workers = os.environ.get('INVENTREE_GUNICORN_WORKERS', None)
|
||||
@@ -40,18 +40,3 @@ max_requests_jitter = 50
|
||||
|
||||
# preload app so that the ready functions are only executed once
|
||||
preload_app = True
|
||||
|
||||
|
||||
def post_fork(server, worker):
|
||||
"""Post-fork hook to set up logging for each worker."""
|
||||
from django.conf import settings
|
||||
|
||||
if not settings.TRACING_ENABLED:
|
||||
return
|
||||
|
||||
# Instrument gunicorm
|
||||
from InvenTree.tracing import setup_instruments, setup_tracing
|
||||
|
||||
# Run tracing/logging instrumentation
|
||||
setup_tracing(**settings.TRACING_DETAILS)
|
||||
setup_instruments(settings.DB_ENGINE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/ash
|
||||
|
||||
# exit when any command fails
|
||||
set -e
|
||||
@@ -40,17 +40,14 @@ if [[ -n "$INVENTREE_PY_ENV" ]]; then
|
||||
if test -d "$INVENTREE_PY_ENV"; then
|
||||
# venv already exists
|
||||
echo "Using Python virtual environment: ${INVENTREE_PY_ENV}"
|
||||
source ${INVENTREE_PY_ENV}/bin/activate
|
||||
else
|
||||
# Setup a virtual environment (within the provided directory)
|
||||
# Setup a virtual environment (within the "data/env" directory)
|
||||
echo "Running first time setup for python environment"
|
||||
python3 -m venv ${INVENTREE_PY_ENV} --system-site-packages --upgrade-deps
|
||||
|
||||
# Ensure invoke tool is installed locally
|
||||
source ${INVENTREE_PY_ENV}/bin/activate
|
||||
python3 -m pip install --ignore-installed --upgrade invoke
|
||||
fi
|
||||
|
||||
# Now activate the venv
|
||||
source ${INVENTREE_PY_ENV}/bin/activate
|
||||
fi
|
||||
|
||||
cd ${INVENTREE_HOME}
|
||||
|
||||
12
contrib/container/install_build_packages.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/ash
|
||||
|
||||
# Install system packages required for building InvenTree python libraries
|
||||
# Note that for postgreslql, we use the 13 version, which matches the version used in the InvenTree docker image
|
||||
|
||||
apk add gcc g++ musl-dev openssl-dev libffi-dev cargo python3-dev openldap-dev \
|
||||
libstdc++ build-base linux-headers py3-grpcio \
|
||||
jpeg-dev openjpeg-dev libwebp-dev zlib-dev \
|
||||
sqlite sqlite-dev \
|
||||
mariadb-connector-c-dev mariadb-client mariadb-dev \
|
||||
postgresql13-dev postgresql-libs \
|
||||
$@
|
||||
@@ -17,7 +17,6 @@ gunicorn>=22.0.0
|
||||
# LDAP required packages
|
||||
django-auth-ldap # Django integration for ldap auth
|
||||
python-ldap # LDAP auth support
|
||||
django<5.0 # Force lower to match main project
|
||||
|
||||
# Upgraded python package installer
|
||||
uv
|
||||
|
||||
@@ -1,256 +1,220 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile contrib/container/requirements.in -o contrib/container/requirements.txt --python-version=3.11 --no-strip-extras --generate-hashes -b src/backend/requirements.txt
|
||||
asgiref==3.10.0 \
|
||||
--hash=sha256:aef8a81283a34d0ab31630c9b7dfe70c812c95eba78171367ca8745e88124734 \
|
||||
--hash=sha256:d89f2d8cd8b56dada7d52fa7dc8075baa08fb836560710d38c292a7a3f78c04e
|
||||
# uv pip compile contrib/container/requirements.in -o contrib/container/requirements.txt --python-version=3.11 --no-strip-extras --generate-hashes
|
||||
asgiref==3.8.1 \
|
||||
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
|
||||
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
|
||||
# via django
|
||||
django==4.2.26 \
|
||||
--hash=sha256:9398e487bcb55e3f142cb56d19fbd9a83e15bb03a97edc31f408361ee76d9d7a \
|
||||
--hash=sha256:c96e64fc3c359d051a6306871bd26243db1bd02317472a62ffdbe6c3cae14280
|
||||
# via
|
||||
# -r contrib/container/requirements.in
|
||||
# django-auth-ldap
|
||||
django-auth-ldap==5.2.0 \
|
||||
--hash=sha256:08ba6efc0340d9874725a962311b14991e29a33593eb150a8fb640709dbfa80f \
|
||||
--hash=sha256:7dc6eb576ba36051850b580e4bdf4464e04bbe7367c3827a3121b4d7c51fb175
|
||||
# via -r contrib/container/requirements.in
|
||||
gunicorn==23.0.0 \
|
||||
--hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \
|
||||
--hash=sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec
|
||||
# via -r contrib/container/requirements.in
|
||||
invoke==2.2.1 \
|
||||
--hash=sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8 \
|
||||
--hash=sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707
|
||||
# via -r contrib/container/requirements.in
|
||||
mariadb==1.1.14 \
|
||||
--hash=sha256:0f5fc74023f2e479be159542633f8b5865fee18a36e5a6d4e262387b39a692ee \
|
||||
--hash=sha256:1a50b4612c0dd5b69690cebb34cef552a7f64dcadeb5aa91d70cd99bf01bc5b3 \
|
||||
--hash=sha256:3d2c795cde606f4e12c0d73282b062433f414cae035675b0d81f2d65c9b79ac5 \
|
||||
--hash=sha256:3f6fdc4ded5e0500a6a29bf0c8bf1be94189dcef5a8d5e0e154a4b3456f86bcc \
|
||||
--hash=sha256:4c7f33578da163a1b79929aae241f5f981d7b9d5a94d89e589aad7ec58e313ea \
|
||||
--hash=sha256:55ddbe5272c292cbcb2968d87681b5d2b327e65646a015e324b8eeb804d14531 \
|
||||
--hash=sha256:5b514362ba3ad3ef7ada91bc8a8b3b4c0e5144efce96b5bffa3dbc46b8af7d7a \
|
||||
--hash=sha256:6659725837e48fa6af05e20128fb525029f706f1921d5dbf639a25b2f80b9f93 \
|
||||
--hash=sha256:685a1ad2a24fd0aae1c4416fe0ac794adc84ab9209c8d0c57078f770d39731db \
|
||||
--hash=sha256:7fd603c5cf23c47ef0d28fdc2b4b79919ee7f75d00ed070d3cd1054dcf816aeb \
|
||||
--hash=sha256:932a95016b7e9b8d78893aa5ee608e74199e3c6dd607dbe5e4da2010a4f67b88 \
|
||||
--hash=sha256:98d552a8bb599eceaa88f65002ad00bd88aeed160592c273a7e5c1d79ab733dd \
|
||||
--hash=sha256:e6d702a53eccf20922e47f2f45cfb5c7a0c2c6c0a46e4ee2d8a80d0ff4a52f34
|
||||
# via -r contrib/container/requirements.in
|
||||
mysqlclient==2.2.7 \
|
||||
--hash=sha256:199dab53a224357dd0cb4d78ca0e54018f9cee9bf9ec68d72db50e0a23569076 \
|
||||
--hash=sha256:201a6faa301011dd07bca6b651fe5aaa546d7c9a5426835a06c3172e1056a3c5 \
|
||||
--hash=sha256:24ae22b59416d5fcce7e99c9d37548350b4565baac82f95e149cac6ce4163845 \
|
||||
--hash=sha256:2e3c11f7625029d7276ca506f8960a7fd3c5a0a0122c9e7404e6a8fe961b3d22 \
|
||||
--hash=sha256:4b4c0200890837fc64014cc938ef2273252ab544c1b12a6c1d674c23943f3f2e \
|
||||
--hash=sha256:92af368ed9c9144737af569c86d3b6c74a012a6f6b792eb868384787b52bb585 \
|
||||
--hash=sha256:977e35244fe6ef44124e9a1c2d1554728a7b76695598e4b92b37dc2130503069 \
|
||||
--hash=sha256:a22d99d26baf4af68ebef430e3131bb5a9b722b79a9fcfac6d9bbf8a88800687
|
||||
# via -r contrib/container/requirements.in
|
||||
packaging==25.0 \
|
||||
--hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \
|
||||
--hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f
|
||||
django==4.2.11 \
|
||||
--hash=sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 \
|
||||
--hash=sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3
|
||||
# via django-auth-ldap
|
||||
django-auth-ldap==4.8.0 \
|
||||
--hash=sha256:4b4b944f3c28bce362f33fb6e8db68429ed8fd8f12f0c0c4b1a4344a7ef225ce \
|
||||
--hash=sha256:604250938ddc9fda619f247c7a59b0b2f06e53a7d3f46a156f28aa30dd71a738
|
||||
gunicorn==22.0.0 \
|
||||
--hash=sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9 \
|
||||
--hash=sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63
|
||||
invoke==2.2.0 \
|
||||
--hash=sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820 \
|
||||
--hash=sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5
|
||||
mariadb==1.1.10 \
|
||||
--hash=sha256:03d6284ef713d1cad40146576a4cc2d6cbc1662060f2a0e59b174e1694521698 \
|
||||
--hash=sha256:1ce87971c02375236ff8933e6c593c748e7b2f2950b86eabfab4289fd250ea63 \
|
||||
--hash=sha256:1d81b22efbaaf4c5bc5e4cc4e2ef3c459538c1a939371089d8c5591d6f26a62e \
|
||||
--hash=sha256:29040e426f877ddc45f337c6eb381b6bbab63cc6bf8431a28effe30162142513 \
|
||||
--hash=sha256:4521aa721f926946bd71491f872e8babc78fa97755ed2114f5684b77363107cb \
|
||||
--hash=sha256:49200378c614984f5ec875481662a49d7c97c2be27970b01b32fa4b7520d4e22 \
|
||||
--hash=sha256:5d652117e2fdf12b9723e7452a05fce9e6ccbae6ea48871b21a3a8fde259dc48 \
|
||||
--hash=sha256:8c8c6b27486b0e1772a23002c702b5fd244eecf9f05633dd6cb345fc26755a20 \
|
||||
--hash=sha256:a332893e3ef7ceb7970ab4bd7c844bcb4bd68a051ca51313566f9808d7411f2d \
|
||||
--hash=sha256:d7b09ec4abd02ed235257feb769f90cd4066e8f536b55b92f5166103d5b66a63 \
|
||||
--hash=sha256:dff8b28ce4044574870d7bdd2d9f9f5da8e5f95a7ff6d226185db733060d1a93
|
||||
mysqlclient==2.2.4 \
|
||||
--hash=sha256:329e4eec086a2336fe3541f1ce095d87a6f169d1cc8ba7b04ac68bcb234c9711 \
|
||||
--hash=sha256:33bc9fb3464e7d7c10b1eaf7336c5ff8f2a3d3b88bab432116ad2490beb3bf41 \
|
||||
--hash=sha256:3c318755e06df599338dad7625f884b8a71fcf322a9939ef78c9b3db93e1de7a \
|
||||
--hash=sha256:4e80dcad884dd6e14949ac6daf769123223a52a6805345608bf49cdaf7bc8b3a \
|
||||
--hash=sha256:9d3310295cb682232cadc28abd172f406c718b9ada41d2371259098ae37779d3 \
|
||||
--hash=sha256:9d4c015480c4a6b2b1602eccd9846103fc70606244788d04aa14b31c4bd1f0e2 \
|
||||
--hash=sha256:ac44777eab0a66c14cb0d38965572f762e193ec2e5c0723bcd11319cc5b693c5 \
|
||||
--hash=sha256:d43987bb9626096a302ca6ddcdd81feaeca65ced1d5fe892a6a66b808326aa54 \
|
||||
--hash=sha256:e1ebe3f41d152d7cb7c265349fdb7f1eca86ccb0ca24a90036cde48e00ceb2ab
|
||||
packaging==24.0 \
|
||||
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
|
||||
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
|
||||
# via
|
||||
# gunicorn
|
||||
# mariadb
|
||||
psycopg[binary, pool]==3.2.11 \
|
||||
--hash=sha256:217231b2b6b72fba88281b94241b2f16043ee67f81def47c52a01b72ff0c086a \
|
||||
--hash=sha256:398bb484ed44361e041c8f804ed7af3d2fcefbffdace1d905b7446c319321706
|
||||
# via -r contrib/container/requirements.in
|
||||
psycopg-binary==3.2.11 \
|
||||
--hash=sha256:00221bfeb9594ca6e01207b032c300fa6f889d918bf0de47f4571c1f9f6e1578 \
|
||||
--hash=sha256:110a2036007230416fcc2c17bfe7aaa2c1fa9b6e9d21e2cd551523e3f6489759 \
|
||||
--hash=sha256:199f88a05dd22133eab2deb30348ef7a70c23d706c8e63fdc904234163c63517 \
|
||||
--hash=sha256:1db270e6bdbd183e3908cd9bb832506b99e1f2222a2fc2145f980c3ba1c8c30f \
|
||||
--hash=sha256:20d41bcd9ac289d44ac1f6151594f7883483b4ad14680a63e04b639dc90c3349 \
|
||||
--hash=sha256:23c77dbbffe8ba679213877f7204f4599bd545b65d2d69982fd685a3fea35b11 \
|
||||
--hash=sha256:260738ae222b41dbefd0d84cb2e150a112f90b41688630f57fdac487ab6d6f38 \
|
||||
--hash=sha256:27eb6367350b75fef882c40cd6f748bfd976db2f8651f7511956f11efc15154f \
|
||||
--hash=sha256:2a438fad4cc081b018431fde0e791b6d50201526edf39522a85164f606c39ddb \
|
||||
--hash=sha256:30e2c114d26554ae677088de5d4133cc112344d7a233200fdbf4a2ca5754c7ec \
|
||||
--hash=sha256:31f1d5630afa673c37a6327f8e3efa1f17d4e4e42972643b3478b52275233529 \
|
||||
--hash=sha256:32bd319a68420631a320bb450921c8320641621a92556c97b38b1e116010c344 \
|
||||
--hash=sha256:3bd2c8fb1dec6f93383fbaa561591fa3d676e079f9cb9889af17c3020a19715f \
|
||||
--hash=sha256:3f32b09fba85d9e239229bdc5b6254420c02054f6954fe7fbd1ecf1ca93009ed \
|
||||
--hash=sha256:478a68d50f34f6203642d245e2046d266c719ab4e593a1bb94c3be5f82e1aee1 \
|
||||
--hash=sha256:47f6cf8a1d02d25238bdb8741ac641ff0ec22b1c6ff6a2acd057d0da5c712842 \
|
||||
--hash=sha256:49d76391b225f72dd63fcab87937ccf307ae0f093b5a382eeacf05f19a57c176 \
|
||||
--hash=sha256:4cae9bdc482e36e825d5102a9f3010e729f33a4ca83fc8a1f439ba16eb61e1f1 \
|
||||
--hash=sha256:54a30f00a51b9043048b3e7ee806ffd31fc5fbd02a20f0e69d21306ff33dc473 \
|
||||
--hash=sha256:566d02a0b85b994e40b4f6276b3423c59e8157f10b73bd2e634f8e0a3dfb1890 \
|
||||
--hash=sha256:5768a9e7d393b2edd3a28de5a6d5850d054a016ed711f7044a9072f19f5e50d5 \
|
||||
--hash=sha256:581358e770a4536e546841b78fd0fe318added4a82443bf22d0bbe3109cf9582 \
|
||||
--hash=sha256:58997db1aa48a1119e26c1c2f893d1c92339bd3be5d1f25334f22eaeaeeca90e \
|
||||
--hash=sha256:58d8f9f80ae79ba7f2a0509424939236220d7d66a4f8256ae999b882cc58065b \
|
||||
--hash=sha256:592fb928efe0674a7400af914bcf931eb5267d36237925947aaecf63bd9a91aa \
|
||||
--hash=sha256:5bc571786a256a2fa2d8f13b5ecf714020b753bc76c2fa6d308e46751946dc31 \
|
||||
--hash=sha256:5f6f948ff1cd252003ff534d7b50a2b25453b4212b283a7514ff8751bdb68c37 \
|
||||
--hash=sha256:5fb27dd9c52ae13cb4de90244207155b694f76a75a816115ead2d573f40e1e36 \
|
||||
--hash=sha256:6688807ed07436c18e9946d01372bc80b9d20b7732cde27de9313e0860910c84 \
|
||||
--hash=sha256:6b9632c42f76d5349e7dd50025cff02688eb760b258e891ad2c6428e7e4917d5 \
|
||||
--hash=sha256:720e19ff2d1c425b6be18bd20ba35010c7927e492bcfecbae1085a89caa7db7c \
|
||||
--hash=sha256:749d23fbfd642a7abfef5fc0f6ca185fa82a2c0f895e6eab42c3f2a5d88f6011 \
|
||||
--hash=sha256:7608c9fa58b85426093ab8777080e8f134d89915c05c51fa270e7aee317f2b38 \
|
||||
--hash=sha256:766089fdaa8af1b5f7e2ec9fd7ad190c865e226b4fb0e7b1bd8dbcd62b5b923e \
|
||||
--hash=sha256:7744b4ed1f3b76fe37de7e9ef98014482fe74b6d3dfe1026cc4cfb4b4404e74f \
|
||||
--hash=sha256:7b3c5474dbad63bcccb8d14d4d4c7c19f1dc6f8e8c1914cbc771d261cf8eddca \
|
||||
--hash=sha256:81e57d1f00af9b7414c8d00ac77892b3786ddd69a23c27dee47cae8fd3543b07 \
|
||||
--hash=sha256:82fe30afbdd66fbdad583b02baad5c15930a3dc8a3756d2ae15fc874e9be8ec8 \
|
||||
--hash=sha256:8792e502a16a0b28d9fd23571fe492271a00c4b2b55f6c0b8377e47032758cd3 \
|
||||
--hash=sha256:91268f04380964a5e767f8102d05f1e23312ddbe848de1a9514b08b3fc57d354 \
|
||||
--hash=sha256:9b4b0fc4e774063ae64c92cc57e2b10160150de68c96d71743218159d953869d \
|
||||
--hash=sha256:9bdc762600fcc8e4ad3224734a4e70cc226207fd8f2de47c36b115efeed01782 \
|
||||
--hash=sha256:9ea3ebe1706fd78d6ac0dd1cf692a77cfacd5ba967c82128f9863a5e48f63c47 \
|
||||
--hash=sha256:9f12a34bddaeffa7840a61163595ec0d70a9db855896865dcfbb731510014484 \
|
||||
--hash=sha256:a3a59d404e1fb8ec47116f66f5adf48a8993a8aac0dad0395a923155fd55ee38 \
|
||||
--hash=sha256:b051aa1e67f0d03ccdb4503d716f22da56229896526f0aa721e5a199baa9e5d4 \
|
||||
--hash=sha256:b2fa94ce40bc4b408149d83a6204fc5e53c3e9d3cd5b749de2e7e9671a049cf7 \
|
||||
--hash=sha256:c45f61202e5691090a697e599997eaffa3ec298209743caa4fd346145acabafe \
|
||||
--hash=sha256:c594c199869099c59c85b9f4423370b6212491fb929e7fcda0da1768761a2c2c \
|
||||
--hash=sha256:d27f51b8ce291da4af749ef850adb4520bfe52c2ff4677402c719ff35af03f00 \
|
||||
--hash=sha256:d59db908d9baaa057a43dd5aa8352f3e3de4b8c57f295172d5fe521e97d6c39d \
|
||||
--hash=sha256:d7e490848d7bedf6c1d2180233a33d31d554a1b0823f80a0236ebb7d3b6caf12 \
|
||||
--hash=sha256:e3b6328bc2f3ca233f9a5f08d266089b96a534eca9ee4e45cb92d0a8d4629d9c \
|
||||
--hash=sha256:e3f5887019dfb094c60e7026968ca3a964ca16305807ba5e43f9a78483767d5f \
|
||||
--hash=sha256:e7575ca710277cc3e9257ff803a3e0e3cb7cc1b7851639cb783a7cd55ebfc815 \
|
||||
--hash=sha256:e7f4dff472a529c9027f294c8842ab535bbed7e2928fe1f4fc28b27f2463d6d5 \
|
||||
--hash=sha256:eab6959fade522e586b8ec37d3fe337ce10861965edef3292f52e66e36dc375d \
|
||||
--hash=sha256:f5e7415b5d0f58edf2708842c66605092df67f3821161d861b09695fc326c4de \
|
||||
--hash=sha256:f72146ad5b69ea177c2707578e5a4a9422b79e50d5a80992dabc5619b0929771 \
|
||||
--hash=sha256:fa2aa5094dc962967ca0978c035b3ef90329b802501ef12a088d3bac6a55598e \
|
||||
--hash=sha256:fe5e3648e855df4fba1d70c18aef18c9880ea8d123fdfae754c18787c8cb37b3 \
|
||||
--hash=sha256:ff64883cff66fe797cd958c0ff7f53fc36a28239b9e0dc80189ce1c03ce47153
|
||||
psycopg[binary, pool]==3.1.18 \
|
||||
--hash=sha256:31144d3fb4c17d78094d9e579826f047d4af1da6a10427d91dfcfb6ecdf6f12b \
|
||||
--hash=sha256:4d5a0a5a8590906daa58ebd5f3cfc34091377354a1acced269dd10faf55da60e
|
||||
psycopg-binary==3.1.18 \
|
||||
--hash=sha256:02bd4da45d5ee9941432e2e9bf36fa71a3ac21c6536fe7366d1bd3dd70d6b1e7 \
|
||||
--hash=sha256:0f68ac2364a50d4cf9bb803b4341e83678668f1881a253e1224574921c69868c \
|
||||
--hash=sha256:13bcd3742112446037d15e360b27a03af4b5afcf767f5ee374ef8f5dd7571b31 \
|
||||
--hash=sha256:1729d0e3dfe2546d823841eb7a3d003144189d6f5e138ee63e5227f8b75276a5 \
|
||||
--hash=sha256:1859aeb2133f5ecdd9cbcee155f5e38699afc06a365f903b1512c765fd8d457e \
|
||||
--hash=sha256:1c9b6bd7fb5c6638cb32469674707649b526acfe786ba6d5a78ca4293d87bae4 \
|
||||
--hash=sha256:247474af262bdd5559ee6e669926c4f23e9cf53dae2d34c4d991723c72196404 \
|
||||
--hash=sha256:258d2f0cb45e4574f8b2fe7c6d0a0e2eb58903a4fd1fbaf60954fba82d595ab7 \
|
||||
--hash=sha256:2e2484ae835dedc80cdc7f1b1a939377dc967fed862262cfd097aa9f50cade46 \
|
||||
--hash=sha256:320047e3d3554b857e16c2b6b615a85e0db6a02426f4d203a4594a2f125dfe57 \
|
||||
--hash=sha256:39242546383f6b97032de7af30edb483d237a0616f6050512eee7b218a2aa8ee \
|
||||
--hash=sha256:3c2b039ae0c45eee4cd85300ef802c0f97d0afc78350946a5d0ec77dd2d7e834 \
|
||||
--hash=sha256:3c7afcd6f1d55992f26d9ff7b0bd4ee6b475eb43aa3f054d67d32e09f18b0065 \
|
||||
--hash=sha256:3e4b0bb91da6f2238dbd4fbb4afc40dfb4f045bb611b92fce4d381b26413c686 \
|
||||
--hash=sha256:3e7ce4d988112ca6c75765c7f24c83bdc476a6a5ce00878df6c140ca32c3e16d \
|
||||
--hash=sha256:4085f56a8d4fc8b455e8f44380705c7795be5317419aa5f8214f315e4205d804 \
|
||||
--hash=sha256:4575da95fc441244a0e2ebaf33a2b2f74164603341d2046b5cde0a9aa86aa7e2 \
|
||||
--hash=sha256:489aa4fe5a0b653b68341e9e44af247dedbbc655326854aa34c163ef1bcb3143 \
|
||||
--hash=sha256:4e4de16a637ec190cbee82e0c2dc4860fed17a23a35f7a1e6dc479a5c6876722 \
|
||||
--hash=sha256:531381f6647fc267383dca88dbe8a70d0feff433a8e3d0c4939201fea7ae1b82 \
|
||||
--hash=sha256:55ff0948457bfa8c0d35c46e3a75193906d1c275538877ba65907fd67aa059ad \
|
||||
--hash=sha256:59701118c7d8842e451f1e562d08e8708b3f5d14974eefbce9374badd723c4ae \
|
||||
--hash=sha256:5c323103dfa663b88204cf5f028e83c77d7a715f9b6f51d2bbc8184b99ddd90a \
|
||||
--hash=sha256:5d6e860edf877d4413e4a807e837d55e3a7c7df701e9d6943c06e460fa6c058f \
|
||||
--hash=sha256:639dd78ac09b144b0119076783cb64e1128cc8612243e9701d1503c816750b2e \
|
||||
--hash=sha256:6432047b8b24ef97e3fbee1d1593a0faaa9544c7a41a2c67d1f10e7621374c83 \
|
||||
--hash=sha256:67284e2e450dc7a9e4d76e78c0bd357dc946334a3d410defaeb2635607f632cd \
|
||||
--hash=sha256:6ebecbf2406cd6875bdd2453e31067d1bd8efe96705a9489ef37e93b50dc6f09 \
|
||||
--hash=sha256:7121acc783c4e86d2d320a7fb803460fab158a7f0a04c5e8c5d49065118c1e73 \
|
||||
--hash=sha256:74e498586b72fb819ca8ea82107747d0cb6e00ae685ea6d1ab3f929318a8ce2d \
|
||||
--hash=sha256:780a90bcb69bf27a8b08bc35b958e974cb6ea7a04cdec69e737f66378a344d68 \
|
||||
--hash=sha256:7ac1785d67241d5074f8086705fa68e046becea27964267ab3abd392481d7773 \
|
||||
--hash=sha256:812726266ab96de681f2c7dbd6b734d327f493a78357fcc16b2ac86ff4f4e080 \
|
||||
--hash=sha256:824a1bfd0db96cc6bef2d1e52d9e0963f5bf653dd5bc3ab519a38f5e6f21c299 \
|
||||
--hash=sha256:87dd9154b757a5fbf6d590f6f6ea75f4ad7b764a813ae04b1d91a70713f414a1 \
|
||||
--hash=sha256:887f8d856c91510148be942c7acd702ccf761a05f59f8abc123c22ab77b5a16c \
|
||||
--hash=sha256:888a72c2aca4316ca6d4a619291b805677bae99bba2f6e31a3c18424a48c7e4d \
|
||||
--hash=sha256:8f54978c4b646dec77fefd8485fa82ec1a87807f334004372af1aaa6de9539a5 \
|
||||
--hash=sha256:91074f78a9f890af5f2c786691575b6b93a4967ad6b8c5a90101f7b8c1a91d9c \
|
||||
--hash=sha256:9d684227ef8212e27da5f2aff9d4d303cc30b27ac1702d4f6881935549486dd5 \
|
||||
--hash=sha256:9e24e7b6a68a51cc3b162d0339ae4e1263b253e887987d5c759652f5692b5efe \
|
||||
--hash=sha256:9ffcbbd389e486d3fd83d30107bbf8b27845a295051ccabde240f235d04ed921 \
|
||||
--hash=sha256:a87e9eeb80ce8ec8c2783f29bce9a50bbcd2e2342a340f159c3326bf4697afa1 \
|
||||
--hash=sha256:ad35ac7fd989184bf4d38a87decfb5a262b419e8ba8dcaeec97848817412c64a \
|
||||
--hash=sha256:b15e3653c82384b043d820fc637199b5c6a36b37fa4a4943e0652785bb2bad5d \
|
||||
--hash=sha256:b293e01057e63c3ac0002aa132a1071ce0fdb13b9ee2b6b45d3abdb3525c597d \
|
||||
--hash=sha256:b2f7f95746efd1be2dc240248cc157f4315db3fd09fef2adfcc2a76e24aa5741 \
|
||||
--hash=sha256:bd27f713f2e5ef3fd6796e66c1a5203a27a30ecb847be27a78e1df8a9a5ae68c \
|
||||
--hash=sha256:c38a4796abf7380f83b1653c2711cb2449dd0b2e5aca1caa75447d6fa5179c69 \
|
||||
--hash=sha256:c76659ae29a84f2c14f56aad305dd00eb685bd88f8c0a3281a9a4bc6bd7d2aa7 \
|
||||
--hash=sha256:c84a0174109f329eeda169004c7b7ca2e884a6305acab4a39600be67f915ed38 \
|
||||
--hash=sha256:cd2a9f7f0d4dacc5b9ce7f0e767ae6cc64153264151f50698898c42cabffec0c \
|
||||
--hash=sha256:d322ba72cde4ca2eefc2196dad9ad7e52451acd2f04e3688d590290625d0c970 \
|
||||
--hash=sha256:d4422af5232699f14b7266a754da49dc9bcd45eba244cf3812307934cd5d6679 \
|
||||
--hash=sha256:d46ae44d66bf6058a812467f6ae84e4e157dee281bfb1cfaeca07dee07452e85 \
|
||||
--hash=sha256:da917f6df8c6b2002043193cb0d74cc173b3af7eb5800ad69c4e1fbac2a71c30 \
|
||||
--hash=sha256:dea4a59da7850192fdead9da888e6b96166e90608cf39e17b503f45826b16f84 \
|
||||
--hash=sha256:e05f6825f8db4428782135e6986fec79b139210398f3710ed4aa6ef41473c008 \
|
||||
--hash=sha256:e1cf59e0bb12e031a48bb628aae32df3d0c98fd6c759cb89f464b1047f0ca9c8 \
|
||||
--hash=sha256:e252d66276c992319ed6cd69a3ffa17538943954075051e992143ccbf6dc3d3e \
|
||||
--hash=sha256:e262398e5d51563093edf30612cd1e20fedd932ad0994697d7781ca4880cdc3d \
|
||||
--hash=sha256:e28ff8f3de7b56588c2a398dc135fd9f157d12c612bd3daa7e6ba9872337f6f5 \
|
||||
--hash=sha256:eea5f14933177ffe5c40b200f04f814258cc14b14a71024ad109f308e8bad414 \
|
||||
--hash=sha256:f876ebbf92db70125f6375f91ab4bc6b27648aa68f90d661b1fc5affb4c9731c \
|
||||
--hash=sha256:f8ff3bc08b43f36fdc24fedb86d42749298a458c4724fb588c4d76823ac39f54
|
||||
# via psycopg
|
||||
psycopg-pool==3.2.6 \
|
||||
--hash=sha256:0f92a7817719517212fbfe2fd58b8c35c1850cdd2a80d36b581ba2085d9148e5 \
|
||||
--hash=sha256:5887318a9f6af906d041a0b1dc1c60f8f0dda8340c2572b74e10907b51ed5da7
|
||||
psycopg-pool==3.2.1 \
|
||||
--hash=sha256:060b551d1b97a8d358c668be58b637780b884de14d861f4f5ecc48b7563aafb7 \
|
||||
--hash=sha256:6509a75c073590952915eddbba7ce8b8332a440a31e77bba69561483492829ad
|
||||
# via psycopg
|
||||
pyasn1==0.6.1 \
|
||||
--hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \
|
||||
--hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034
|
||||
pyasn1==0.6.0 \
|
||||
--hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \
|
||||
--hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473
|
||||
# via
|
||||
# pyasn1-modules
|
||||
# python-ldap
|
||||
pyasn1-modules==0.4.2 \
|
||||
--hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \
|
||||
--hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6
|
||||
pyasn1-modules==0.4.0 \
|
||||
--hash=sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6 \
|
||||
--hash=sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b
|
||||
# via python-ldap
|
||||
python-ldap==3.4.5 \
|
||||
--hash=sha256:b2f6ef1c37fe2c6a5a85212efe71311ee21847766a7d45fcb711f3b270a5f79a
|
||||
# via
|
||||
# -r contrib/container/requirements.in
|
||||
# django-auth-ldap
|
||||
pyyaml==6.0.3 \
|
||||
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
|
||||
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
|
||||
--hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \
|
||||
--hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \
|
||||
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
|
||||
--hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \
|
||||
--hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \
|
||||
--hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \
|
||||
--hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \
|
||||
--hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \
|
||||
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
|
||||
--hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \
|
||||
--hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \
|
||||
--hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \
|
||||
--hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \
|
||||
--hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \
|
||||
--hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \
|
||||
--hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \
|
||||
--hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \
|
||||
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
|
||||
--hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \
|
||||
--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
|
||||
--hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \
|
||||
--hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \
|
||||
--hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \
|
||||
--hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \
|
||||
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
|
||||
--hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \
|
||||
--hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \
|
||||
--hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \
|
||||
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
|
||||
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
|
||||
--hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \
|
||||
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
|
||||
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
|
||||
--hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \
|
||||
--hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \
|
||||
--hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \
|
||||
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
|
||||
--hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \
|
||||
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
|
||||
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \
|
||||
--hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \
|
||||
--hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \
|
||||
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
|
||||
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
|
||||
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
|
||||
--hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \
|
||||
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
|
||||
--hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \
|
||||
--hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \
|
||||
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
|
||||
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
|
||||
--hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \
|
||||
--hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \
|
||||
--hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \
|
||||
--hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \
|
||||
--hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \
|
||||
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
|
||||
--hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \
|
||||
--hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \
|
||||
--hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \
|
||||
--hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \
|
||||
--hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \
|
||||
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
|
||||
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
|
||||
--hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \
|
||||
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
|
||||
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
||||
--hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \
|
||||
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
|
||||
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
|
||||
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
|
||||
# via -r contrib/container/requirements.in
|
||||
setuptools==80.9.0 \
|
||||
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \
|
||||
--hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c
|
||||
# via -r contrib/container/requirements.in
|
||||
sqlparse==0.5.3 \
|
||||
--hash=sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272 \
|
||||
--hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca
|
||||
python-ldap==3.4.4 \
|
||||
--hash=sha256:7edb0accec4e037797705f3a05cbf36a9fde50d08c8f67f2aef99a2628fab828
|
||||
# via django-auth-ldap
|
||||
pyyaml==6.0.1 \
|
||||
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
|
||||
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
|
||||
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
|
||||
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
|
||||
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
|
||||
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
|
||||
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
|
||||
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
|
||||
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
|
||||
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
|
||||
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
|
||||
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
|
||||
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
|
||||
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
|
||||
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
|
||||
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
|
||||
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
|
||||
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
|
||||
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
|
||||
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
|
||||
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
|
||||
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
|
||||
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
|
||||
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
|
||||
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
|
||||
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
|
||||
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
|
||||
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
|
||||
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
|
||||
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
|
||||
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
|
||||
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
|
||||
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
|
||||
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
|
||||
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
|
||||
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
|
||||
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
|
||||
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
|
||||
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
|
||||
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
|
||||
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
|
||||
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
|
||||
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
|
||||
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
|
||||
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
|
||||
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
|
||||
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
|
||||
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
|
||||
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
|
||||
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
|
||||
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
|
||||
setuptools==69.5.1 \
|
||||
--hash=sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987 \
|
||||
--hash=sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32
|
||||
sqlparse==0.5.0 \
|
||||
--hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \
|
||||
--hash=sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663
|
||||
# via django
|
||||
typing-extensions==4.15.0 \
|
||||
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
|
||||
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
|
||||
typing-extensions==4.11.0 \
|
||||
--hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \
|
||||
--hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a
|
||||
# via
|
||||
# psycopg
|
||||
# psycopg-pool
|
||||
uv==0.9.7 \
|
||||
--hash=sha256:0fdbfad5b367e7a3968264af6da5bbfffd4944a90319042f166e8df1a2d9de09 \
|
||||
--hash=sha256:134e0daac56f9e399ccdfc9e4635bc0a13c234cad9224994c67bae462e07399a \
|
||||
--hash=sha256:1aaf79b4234400e9e2fbf5b50b091726ccbb0b6d4d032edd3dfd4c9673d89dca \
|
||||
--hash=sha256:34fe0af83fcafb9e2b786f4bd633a06c878d548a7c479594ffb5607db8778471 \
|
||||
--hash=sha256:555ee72146b8782c73d755e4a21c9885c6bfc81db0ffca2220d52dddae007eb7 \
|
||||
--hash=sha256:56a440ccde7624a7bc070e1c2492b358c67aea9b8f17bc243ea27c5871c8d02c \
|
||||
--hash=sha256:62b315f62669899076a1953fba6baf50bd2b57f66f656280491331dcedd7e6c6 \
|
||||
--hash=sha256:635e82c2d0d8b001618af82e4f2724350f15814f6462a71b3ebd44adec21f03c \
|
||||
--hash=sha256:7019f4416925f4091b9d28c1cf3e8444cf910c4ede76bdf1f6b9a56ca5f97985 \
|
||||
--hash=sha256:777bb1de174319245a35e4f805d3b4484d006ebedae71d3546f95e7c28a5f436 \
|
||||
--hash=sha256:89697fa0d7384ba047daf75df844ee7800235105e41d08e0c876861a2b4aa90e \
|
||||
--hash=sha256:8cf6bc2482d1293cc630f66b862b494c09acda9b7faff7307ef52667a2b3ad49 \
|
||||
--hash=sha256:b5f1fb8203a77853db176000e8f30d5815ab175dc46199db059f97a72fc51110 \
|
||||
--hash=sha256:bb8bfcc2897f7653522abc2cae80233af756ad857bfbbbbe176f79460cbba417 \
|
||||
--hash=sha256:bcf878528bd079fe8ae15928b5dfa232fac8b0e1854a2102da6ae1a833c31276 \
|
||||
--hash=sha256:c9810ee8173dce129c49b338d5e97f3d7c7e9435f73e0b9b26c2f37743d3bb9e \
|
||||
--hash=sha256:d13da6521d4e841b1e0a9fda82e793dcf8458a323a9e8955f50903479d0bfa97 \
|
||||
--hash=sha256:d6e5fe28ca05a4b576c0e8da5f69251dc187a67054829cfc4afb2bfa1767114b \
|
||||
--hash=sha256:edd768f6730bba06aa10fdbd80ee064569f7236806f636bf65b68136a430aad0
|
||||
# via -r contrib/container/requirements.in
|
||||
wheel==0.45.1 \
|
||||
--hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \
|
||||
--hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
|
||||
# via -r contrib/container/requirements.in
|
||||
uv==0.1.38 \
|
||||
--hash=sha256:03242a734a572733f2b9a5dbb94517e918fe26fc01114b7c51d12296dfbb8f8b \
|
||||
--hash=sha256:067af2d986329db4fa3c7373017d49f0e16ddff23e483b7e5bc3a5a18ce08ea6 \
|
||||
--hash=sha256:0937ad16ae0e0b6bb6dd3c386f8fb33141ad08d1762eaacffb4d2b27fb466a17 \
|
||||
--hash=sha256:0e1d64ac437b0a14fbcec55b1c3f162fa24860711e0d855fcd9c672b149a122a \
|
||||
--hash=sha256:1be7aa46936c0351ccb1400ea95e5381b3f05fef772fa3b9f23af728cc175dea \
|
||||
--hash=sha256:309e73a3ec3a5a536a3efaf434270fc94b483069f1425765165c1c9d786c27fd \
|
||||
--hash=sha256:4251f9771d392d7badc1e5fb934b397b12ca00fef9d955207ade169cc1f7e872 \
|
||||
--hash=sha256:43772e7589f70e954b1ae29230e575ef9e4d8d769138a94dfa5ae7eaf1e26ac5 \
|
||||
--hash=sha256:4a6024256d38b77151e32876be9fcb99cf75df7a86b26e0161cc202bed558adf \
|
||||
--hash=sha256:5a98d6aacd4b57b7e00daf154919e7c9206fefdf40bd28cfb13efe0e0324d491 \
|
||||
--hash=sha256:8de6dbd8f348ee90af044f4cc7b6650521d25ba2d20a813c1e157a3f90069dd9 \
|
||||
--hash=sha256:9133e24db9bdd4f412eab69586d03294419825432a9a27ee1b510a4c01eb7b0b \
|
||||
--hash=sha256:92f65b6e4e5c8126501785af3629dc537d7c82caa56ac9336a86929c73d0e138 \
|
||||
--hash=sha256:afd85029923e712b6b2c45ddc1680c785392220876c766521e45778db3f71f8e \
|
||||
--hash=sha256:b0b15e51a0f8240969bc412ed0dd60cfe3f664b30173139ef263d71c596d631f \
|
||||
--hash=sha256:ea44c07605d1359a7d82bf42706dd86d341f15f4ca2e1f36e51626a7111c2ad5 \
|
||||
--hash=sha256:f87c9711493c53d32012a96b49c4d53aabdf7ed666cbf2c3fb55dd402a6b31a8
|
||||
wheel==0.43.0 \
|
||||
--hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \
|
||||
--hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81
|
||||
|
||||
@@ -23,7 +23,7 @@ port = 127.0.0.1:9001
|
||||
; InvenTree Web Server Process
|
||||
[program:inventree-server]
|
||||
user=inventree
|
||||
directory=/home/inventree/src/src/backend/InvenTree
|
||||
directory=/home/inventree/src/InvenTree
|
||||
command=/home/inventree/env/bin/gunicorn -c gunicorn.conf.py InvenTree.wsgi
|
||||
startsecs=10
|
||||
autostart=true
|
||||
@@ -36,7 +36,7 @@ stdout_logfile=/home/inventree/log/server.out.log
|
||||
; InvenTree Background Worker Process
|
||||
[program:inventree-cluster]
|
||||
user=inventree
|
||||
directory=/home/inventree/src/src/backend/InvenTree
|
||||
directory=/home/inventree/src/InvenTree
|
||||
command=/home/inventree/env/bin/python manage.py qcluster
|
||||
startsecs=10
|
||||
autostart=true
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Packages needed for CI/packages
|
||||
requests==2.32.5
|
||||
pyyaml==6.0.3
|
||||
jc==1.25.6
|
||||
requests==2.31.0
|
||||
pyyaml==6.0.1
|
||||
jc==1.25.2
|
||||
|
||||
@@ -1,281 +1,228 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --no-strip-extras --generate-hashes -b src/backend/requirements.txt
|
||||
certifi==2025.10.5 \
|
||||
--hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \
|
||||
--hash=sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43
|
||||
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --python-version=3.9 --no-strip-extras --generate-hashes
|
||||
certifi==2024.2.2 \
|
||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||
# via requests
|
||||
charset-normalizer==3.4.4 \
|
||||
--hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \
|
||||
--hash=sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93 \
|
||||
--hash=sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394 \
|
||||
--hash=sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89 \
|
||||
--hash=sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc \
|
||||
--hash=sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86 \
|
||||
--hash=sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63 \
|
||||
--hash=sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d \
|
||||
--hash=sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f \
|
||||
--hash=sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8 \
|
||||
--hash=sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0 \
|
||||
--hash=sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505 \
|
||||
--hash=sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161 \
|
||||
--hash=sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af \
|
||||
--hash=sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152 \
|
||||
--hash=sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318 \
|
||||
--hash=sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72 \
|
||||
--hash=sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4 \
|
||||
--hash=sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e \
|
||||
--hash=sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3 \
|
||||
--hash=sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576 \
|
||||
--hash=sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c \
|
||||
--hash=sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1 \
|
||||
--hash=sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8 \
|
||||
--hash=sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1 \
|
||||
--hash=sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2 \
|
||||
--hash=sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44 \
|
||||
--hash=sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26 \
|
||||
--hash=sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88 \
|
||||
--hash=sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016 \
|
||||
--hash=sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede \
|
||||
--hash=sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf \
|
||||
--hash=sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a \
|
||||
--hash=sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc \
|
||||
--hash=sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0 \
|
||||
--hash=sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84 \
|
||||
--hash=sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db \
|
||||
--hash=sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1 \
|
||||
--hash=sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7 \
|
||||
--hash=sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed \
|
||||
--hash=sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8 \
|
||||
--hash=sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133 \
|
||||
--hash=sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e \
|
||||
--hash=sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef \
|
||||
--hash=sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14 \
|
||||
--hash=sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2 \
|
||||
--hash=sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0 \
|
||||
--hash=sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d \
|
||||
--hash=sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828 \
|
||||
--hash=sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f \
|
||||
--hash=sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf \
|
||||
--hash=sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6 \
|
||||
--hash=sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328 \
|
||||
--hash=sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090 \
|
||||
--hash=sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa \
|
||||
--hash=sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381 \
|
||||
--hash=sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c \
|
||||
--hash=sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb \
|
||||
--hash=sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc \
|
||||
--hash=sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a \
|
||||
--hash=sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec \
|
||||
--hash=sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc \
|
||||
--hash=sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac \
|
||||
--hash=sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e \
|
||||
--hash=sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313 \
|
||||
--hash=sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569 \
|
||||
--hash=sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3 \
|
||||
--hash=sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d \
|
||||
--hash=sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525 \
|
||||
--hash=sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894 \
|
||||
--hash=sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3 \
|
||||
--hash=sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9 \
|
||||
--hash=sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a \
|
||||
--hash=sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9 \
|
||||
--hash=sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14 \
|
||||
--hash=sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25 \
|
||||
--hash=sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50 \
|
||||
--hash=sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf \
|
||||
--hash=sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1 \
|
||||
--hash=sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3 \
|
||||
--hash=sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac \
|
||||
--hash=sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e \
|
||||
--hash=sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815 \
|
||||
--hash=sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c \
|
||||
--hash=sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6 \
|
||||
--hash=sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6 \
|
||||
--hash=sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e \
|
||||
--hash=sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4 \
|
||||
--hash=sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84 \
|
||||
--hash=sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69 \
|
||||
--hash=sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15 \
|
||||
--hash=sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191 \
|
||||
--hash=sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0 \
|
||||
--hash=sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897 \
|
||||
--hash=sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd \
|
||||
--hash=sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2 \
|
||||
--hash=sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794 \
|
||||
--hash=sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d \
|
||||
--hash=sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074 \
|
||||
--hash=sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3 \
|
||||
--hash=sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224 \
|
||||
--hash=sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838 \
|
||||
--hash=sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a \
|
||||
--hash=sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d \
|
||||
--hash=sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d \
|
||||
--hash=sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f \
|
||||
--hash=sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8 \
|
||||
--hash=sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490 \
|
||||
--hash=sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966 \
|
||||
--hash=sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9 \
|
||||
--hash=sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3 \
|
||||
--hash=sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e \
|
||||
--hash=sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
|
||||
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
|
||||
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
|
||||
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
|
||||
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
|
||||
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
|
||||
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
|
||||
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
|
||||
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
|
||||
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
|
||||
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
|
||||
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
|
||||
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
|
||||
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
|
||||
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
|
||||
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
|
||||
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
|
||||
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
|
||||
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
|
||||
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
|
||||
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
|
||||
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
|
||||
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
|
||||
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
|
||||
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
|
||||
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
|
||||
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
|
||||
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
|
||||
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
|
||||
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
|
||||
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
|
||||
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
|
||||
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
|
||||
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
|
||||
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
|
||||
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
|
||||
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
|
||||
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
|
||||
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
|
||||
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
|
||||
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
|
||||
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
|
||||
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
|
||||
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
|
||||
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
|
||||
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
|
||||
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
|
||||
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
|
||||
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
|
||||
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
|
||||
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
|
||||
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
|
||||
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
|
||||
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
|
||||
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
|
||||
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
|
||||
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
|
||||
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
|
||||
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
|
||||
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
|
||||
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
|
||||
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
|
||||
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
|
||||
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
|
||||
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
|
||||
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
|
||||
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
|
||||
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
|
||||
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
|
||||
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
|
||||
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
|
||||
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
|
||||
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
|
||||
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
|
||||
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
|
||||
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
|
||||
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
|
||||
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
|
||||
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
|
||||
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
|
||||
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
|
||||
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
|
||||
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
|
||||
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
|
||||
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
|
||||
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
|
||||
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
|
||||
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
|
||||
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
|
||||
# via requests
|
||||
idna==3.11 \
|
||||
--hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
|
||||
--hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902
|
||||
idna==3.7 \
|
||||
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
|
||||
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
|
||||
# via requests
|
||||
jc==1.25.6 \
|
||||
--hash=sha256:27f58befc7ae0a4c63322926c5f1ec892e3eac4a065eff3b07cfe420a6924a07 \
|
||||
--hash=sha256:7367b59e6e0da8babeede1e5b0da083f3c5aa6b6e585b4aed28dd7c4b2d76162
|
||||
# via -r contrib/dev_reqs/requirements.in
|
||||
pygments==2.19.2 \
|
||||
--hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
|
||||
--hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
|
||||
jc==1.25.2 \
|
||||
--hash=sha256:26e412a65a478f9da3097653db6277f915cfae5c0f0a3f42026b405936abd358 \
|
||||
--hash=sha256:97ada193495f79550f06fe0cbfb119ff470bcca57c1cc593a5cdb0008720e0b3
|
||||
pygments==2.17.2 \
|
||||
--hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
|
||||
--hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
|
||||
# via jc
|
||||
pyyaml==6.0.3 \
|
||||
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
|
||||
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
|
||||
--hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \
|
||||
--hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \
|
||||
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
|
||||
--hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \
|
||||
--hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \
|
||||
--hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \
|
||||
--hash=sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0 \
|
||||
--hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \
|
||||
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
|
||||
--hash=sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6 \
|
||||
--hash=sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7 \
|
||||
--hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \
|
||||
--hash=sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007 \
|
||||
--hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \
|
||||
--hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \
|
||||
--hash=sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9 \
|
||||
--hash=sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295 \
|
||||
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
|
||||
--hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \
|
||||
--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
|
||||
--hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \
|
||||
--hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \
|
||||
--hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \
|
||||
--hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \
|
||||
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
|
||||
--hash=sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b \
|
||||
--hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \
|
||||
--hash=sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5 \
|
||||
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
|
||||
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
|
||||
--hash=sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369 \
|
||||
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
|
||||
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
|
||||
--hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \
|
||||
--hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \
|
||||
--hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \
|
||||
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
|
||||
--hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \
|
||||
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
|
||||
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \
|
||||
--hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \
|
||||
--hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \
|
||||
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
|
||||
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
|
||||
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
|
||||
--hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \
|
||||
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
|
||||
--hash=sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4 \
|
||||
--hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \
|
||||
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
|
||||
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
|
||||
--hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \
|
||||
--hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \
|
||||
--hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \
|
||||
--hash=sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da \
|
||||
--hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \
|
||||
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
|
||||
--hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \
|
||||
--hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \
|
||||
--hash=sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f \
|
||||
--hash=sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917 \
|
||||
--hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \
|
||||
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
|
||||
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
|
||||
--hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \
|
||||
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
|
||||
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
||||
--hash=sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3 \
|
||||
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
|
||||
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
|
||||
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
|
||||
# via -r contrib/dev_reqs/requirements.in
|
||||
requests==2.32.5 \
|
||||
--hash=sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 \
|
||||
--hash=sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf
|
||||
# via -r contrib/dev_reqs/requirements.in
|
||||
ruamel-yaml==0.18.15 \
|
||||
--hash=sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701 \
|
||||
--hash=sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700
|
||||
pyyaml==6.0.1 \
|
||||
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
|
||||
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
|
||||
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
|
||||
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
|
||||
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
|
||||
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
|
||||
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
|
||||
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
|
||||
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
|
||||
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
|
||||
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
|
||||
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
|
||||
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
|
||||
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
|
||||
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
|
||||
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
|
||||
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
|
||||
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
|
||||
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
|
||||
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
|
||||
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
|
||||
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
|
||||
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
|
||||
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
|
||||
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
|
||||
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
|
||||
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
|
||||
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
|
||||
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
|
||||
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
|
||||
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
|
||||
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
|
||||
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
|
||||
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
|
||||
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
|
||||
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
|
||||
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
|
||||
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
|
||||
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
|
||||
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
|
||||
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
|
||||
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
|
||||
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
|
||||
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
|
||||
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
|
||||
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
|
||||
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
|
||||
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
|
||||
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
|
||||
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
|
||||
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
|
||||
requests==2.31.0 \
|
||||
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
|
||||
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
|
||||
ruamel-yaml==0.18.6 \
|
||||
--hash=sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636 \
|
||||
--hash=sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b
|
||||
# via jc
|
||||
ruamel-yaml-clib==0.2.14 \
|
||||
--hash=sha256:090782b5fb9d98df96509eecdbcaffd037d47389a89492320280d52f91330d78 \
|
||||
--hash=sha256:0a54e5e40a7a691a426c2703b09b0d61a14294d25cfacc00631aa6f9c964df0d \
|
||||
--hash=sha256:10d9595b6a19778f3269399eff6bab642608e5966183abc2adbe558a42d4efc9 \
|
||||
--hash=sha256:16a60d69f4057ad9a92f3444e2367c08490daed6428291aa16cefb445c29b0e9 \
|
||||
--hash=sha256:18c041b28f3456ddef1f1951d4492dbebe0f8114157c1b3c981a4611c2020792 \
|
||||
--hash=sha256:1c1acc3a0209ea9042cc3cfc0790edd2eddd431a2ec3f8283d081e4d5018571e \
|
||||
--hash=sha256:1f118b707eece8cf84ecbc3e3ec94d9db879d85ed608f95870d39b2d2efa5dca \
|
||||
--hash=sha256:2070bf0ad1540d5c77a664de07ebcc45eebd1ddcab71a7a06f26936920692beb \
|
||||
--hash=sha256:26a8de280ab0d22b6e3ec745b4a5a07151a0f74aad92dd76ab9c8d8d7087720d \
|
||||
--hash=sha256:275f938692013a3883edbd848edde6d9f26825d65c9a2eb1db8baa1adc96a05d \
|
||||
--hash=sha256:27c070cf3888e90d992be75dd47292ff9aa17dafd36492812a6a304a1aedc182 \
|
||||
--hash=sha256:29757bdb7c142f9595cc1b62ec49a3d1c83fab9cef92db52b0ccebaad4eafb98 \
|
||||
--hash=sha256:4ccba93c1e5a40af45b2f08e4591969fa4697eae951c708f3f83dcbf9f6c6bb1 \
|
||||
--hash=sha256:4f4a150a737fccae13fb51234d41304ff2222e3b7d4c8e9428ed1a6ab48389b8 \
|
||||
--hash=sha256:557df28dbccf79b152fe2d1b935f6063d9cc431199ea2b0e84892f35c03bb0ee \
|
||||
--hash=sha256:5ac5ff9425d8acb8f59ac5b96bcb7fd3d272dc92d96a7c730025928ffcc88a7a \
|
||||
--hash=sha256:5bae1a073ca4244620425cd3d3aa9746bde590992b98ee8c7c8be8c597ca0d4e \
|
||||
--hash=sha256:5e56ac47260c0eed992789fa0b8efe43404a9adb608608631a948cee4fc2b052 \
|
||||
--hash=sha256:6aeadc170090ff1889f0d2c3057557f9cd71f975f17535c26a5d37af98f19c27 \
|
||||
--hash=sha256:6d5472f63a31b042aadf5ed28dd3ef0523da49ac17f0463e10fda9c4a2773352 \
|
||||
--hash=sha256:70eda7703b8126f5e52fcf276e6c0f40b0d314674f896fc58c47b0aef2b9ae83 \
|
||||
--hash=sha256:7df6f6e9d0e33c7b1d435defb185095386c469109de723d514142632a7b9d07f \
|
||||
--hash=sha256:7e4f9da7e7549946e02a6122dcad00b7c1168513acb1f8a726b1aaf504a99d32 \
|
||||
--hash=sha256:803f5044b13602d58ea378576dd75aa759f52116a0232608e8fdada4da33752e \
|
||||
--hash=sha256:808c7190a0fe7ae7014c42f73897cf8e9ef14ff3aa533450e51b1e72ec5239ad \
|
||||
--hash=sha256:81f6d3b19bc703679a5705c6a16dabdc79823c71d791d73c65949be7f3012c02 \
|
||||
--hash=sha256:83bbd8354f6abb3fdfb922d1ed47ad8d1db3ea72b0523dac8d07cdacfe1c0fcf \
|
||||
--hash=sha256:8dd3c2cc49caa7a8d64b67146462aed6723a0495e44bf0aa0a2e94beaa8432f6 \
|
||||
--hash=sha256:915748cfc25b8cfd81b14d00f4bfdb2ab227a30d6d43459034533f4d1c207a2a \
|
||||
--hash=sha256:94f3efb718f8f49b031f2071ec7a27dd20cbfe511b4dfd54ecee54c956da2b31 \
|
||||
--hash=sha256:9bd8fe07f49c170e09d76773fb86ad9135e0beee44f36e1576a201b0676d3d1d \
|
||||
--hash=sha256:9bf6b699223afe6c7fe9f2ef76e0bfa6dd892c21e94ce8c957478987ade76cd8 \
|
||||
--hash=sha256:a05ba88adf3d7189a974b2de7a9d56731548d35dc0a822ec3dc669caa7019b29 \
|
||||
--hash=sha256:a0ac90efbc7a77b0d796c03c8cc4e62fd710b3f1e4c32947713ef2ef52e09543 \
|
||||
--hash=sha256:a0cb71ccc6ef9ce36eecb6272c81afdc2f565950cdcec33ae8e6cd8f7fc86f27 \
|
||||
--hash=sha256:a37f40a859b503304dd740686359fcf541d6fb3ff7fc10f539af7f7150917c68 \
|
||||
--hash=sha256:a911aa73588d9a8b08d662b9484bc0567949529824a55d3885b77e8dd62a127a \
|
||||
--hash=sha256:aef953f3b8bd0b50bd52a2e52fb54a6a2171a1889d8dea4a5959d46c6624c451 \
|
||||
--hash=sha256:b28caeaf3e670c08cb7e8de221266df8494c169bd6ed8875493fab45be9607a4 \
|
||||
--hash=sha256:b30110b29484adc597df6bd92a37b90e63a8c152ca8136aad100a02f8ba6d1b6 \
|
||||
--hash=sha256:b5b0f7e294700b615a3bcf6d28b26e6da94e8eba63b079f4ec92e9ba6c0d6b54 \
|
||||
--hash=sha256:c099cafc1834d3c5dac305865d04235f7c21c167c8dd31ebc3d6bbc357e2f023 \
|
||||
--hash=sha256:d73a0187718f6eec5b2f729b0f98e4603f7bd9c48aa65d01227d1a5dcdfbe9e8 \
|
||||
--hash=sha256:d8354515ab62f95a07deaf7f845886cc50e2f345ceab240a3d2d09a9f7d77853 \
|
||||
--hash=sha256:dba72975485f2b87b786075e18a6e5d07dc2b4d8973beb2732b9b2816f1bad70 \
|
||||
--hash=sha256:dd7546c851e59c06197a7c651335755e74aa383a835878ca86d2c650c07a2f85 \
|
||||
--hash=sha256:df3ec9959241d07bc261f4983d25a1205ff37703faf42b474f15d54d88b4f8c9 \
|
||||
--hash=sha256:e1d1735d97fd8a48473af048739379975651fab186f8a25a9f683534e6904179 \
|
||||
--hash=sha256:e501c096aa3889133d674605ebd018471bc404a59cbc17da3c5924421c54d97c \
|
||||
--hash=sha256:e7cb9ad1d525d40f7d87b6df7c0ff916a66bc52cb61b66ac1b2a16d0c1b07640 \
|
||||
--hash=sha256:f4e97a1cf0b7a30af9e1d9dad10a5671157b9acee790d9e26996391f49b965a2 \
|
||||
--hash=sha256:f8b2acb0ffdd2ce8208accbec2dca4a06937d556fdcaefd6473ba1b5daa7e3c4 \
|
||||
--hash=sha256:fb04c5650de6668b853623eceadcdb1a9f2fee381f5d7b6bc842ee7c239eeec4 \
|
||||
--hash=sha256:fbc08c02e9b147a11dfcaa1ac8a83168b699863493e183f7c0c8b12850b7d259 \
|
||||
--hash=sha256:ff86876889ea478b1381089e55cf9e345707b312beda4986f823e1d95e8c0f59
|
||||
ruamel-yaml-clib==0.2.8 \
|
||||
--hash=sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d \
|
||||
--hash=sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001 \
|
||||
--hash=sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462 \
|
||||
--hash=sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9 \
|
||||
--hash=sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe \
|
||||
--hash=sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b \
|
||||
--hash=sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b \
|
||||
--hash=sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615 \
|
||||
--hash=sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62 \
|
||||
--hash=sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15 \
|
||||
--hash=sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b \
|
||||
--hash=sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1 \
|
||||
--hash=sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9 \
|
||||
--hash=sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675 \
|
||||
--hash=sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899 \
|
||||
--hash=sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7 \
|
||||
--hash=sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7 \
|
||||
--hash=sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312 \
|
||||
--hash=sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa \
|
||||
--hash=sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91 \
|
||||
--hash=sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b \
|
||||
--hash=sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6 \
|
||||
--hash=sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3 \
|
||||
--hash=sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334 \
|
||||
--hash=sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5 \
|
||||
--hash=sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3 \
|
||||
--hash=sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe \
|
||||
--hash=sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c \
|
||||
--hash=sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed \
|
||||
--hash=sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337 \
|
||||
--hash=sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880 \
|
||||
--hash=sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f \
|
||||
--hash=sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d \
|
||||
--hash=sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248 \
|
||||
--hash=sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d \
|
||||
--hash=sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf \
|
||||
--hash=sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512 \
|
||||
--hash=sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069 \
|
||||
--hash=sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb \
|
||||
--hash=sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942 \
|
||||
--hash=sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d \
|
||||
--hash=sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31 \
|
||||
--hash=sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92 \
|
||||
--hash=sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5 \
|
||||
--hash=sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28 \
|
||||
--hash=sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d \
|
||||
--hash=sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1 \
|
||||
--hash=sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2 \
|
||||
--hash=sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875 \
|
||||
--hash=sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412
|
||||
# via ruamel-yaml
|
||||
urllib3==2.5.0 \
|
||||
--hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \
|
||||
--hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc
|
||||
urllib3==2.2.1 \
|
||||
--hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
|
||||
--hash=sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19
|
||||
# via requests
|
||||
xmltodict==1.0.2 \
|
||||
--hash=sha256:54306780b7c2175a3967cad1db92f218207e5bc1aba697d887807c0fb68b7649 \
|
||||
--hash=sha256:62d0fddb0dcbc9f642745d8bbf4d81fd17d6dfaec5a15b5c1876300aad92af0d
|
||||
xmltodict==0.13.0 \
|
||||
--hash=sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56 \
|
||||
--hash=sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852
|
||||
# via jc
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# This script was generated by bashly 1.3.3 (https://bashly.dev)
|
||||
# This script was generated by bashly 1.1.1 (https://bashly.dannyb.co)
|
||||
# Modifying it manually is not recommended
|
||||
|
||||
if ((BASH_VERSINFO[0] < 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 2))); then
|
||||
printf "bash version 4.2 or higher is required\n" >&2
|
||||
if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
|
||||
printf "bash version 4 or higher is required\n" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -15,7 +15,7 @@ root_command() {
|
||||
no_call=${args[--no-call]}
|
||||
dry_run=${args[--dry-run]}
|
||||
|
||||
REQS="wget apt-transport-https curl gpg"
|
||||
REQS="wget apt-transport-https"
|
||||
|
||||
function do_call() {
|
||||
if [[ $dry_run ]]; then
|
||||
@@ -56,16 +56,17 @@ root_command() {
|
||||
get_distribution
|
||||
echo "### Detected distribution: $OS $VER"
|
||||
SUPPORTED=true # is this OS supported?
|
||||
NEEDS_LIBSSL1_1=false # does this OS need libssl1.1?
|
||||
|
||||
DIST_OS=${OS,,}
|
||||
DIST_VER=$VER
|
||||
|
||||
case "$OS" in
|
||||
Ubuntu)
|
||||
if [[ $VER == "24.04" ]]; then
|
||||
SUPPORTED=true
|
||||
elif [[ $VER == "22.04" ]]; then
|
||||
if [[ $VER == "22.04" ]]; then
|
||||
SUPPORTED=true
|
||||
NEEDS_LIBSSL1_1=true
|
||||
DIST_VER="20.04"
|
||||
elif [[ $VER == "20.04" ]]; then
|
||||
SUPPORTED=true
|
||||
else
|
||||
@@ -109,6 +110,15 @@ root_command() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $NEEDS_LIBSSL1_1 == "true" ]]; then
|
||||
echo "### Installing libssl1.1"
|
||||
|
||||
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
|
||||
do_call "sudo apt-get update"
|
||||
do_call "sudo apt-get install libssl1.1"
|
||||
sudo rm /etc/apt/sources.list.d/focal-security.list
|
||||
fi
|
||||
|
||||
echo "### Getting and adding key"
|
||||
curl -fsSL https://dl.packager.io/srv/$publisher/InvenTree/key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/pkgr-inventree.gpg > /dev/null
|
||||
echo "### Adding package source"
|
||||
@@ -135,7 +145,15 @@ version_command() {
|
||||
}
|
||||
|
||||
install.sh_usage() {
|
||||
printf "install.sh - Interactive installer for InvenTree\n\n"
|
||||
if [[ -n $long_usage ]]; then
|
||||
printf "install.sh - Interactive installer for InvenTree\n"
|
||||
echo
|
||||
|
||||
else
|
||||
printf "install.sh - Interactive installer for InvenTree\n"
|
||||
echo
|
||||
|
||||
fi
|
||||
|
||||
printf "%s\n" "Usage:"
|
||||
printf " install.sh [SOURCE] [PUBLISHER] [OPTIONS]\n"
|
||||
@@ -143,7 +161,7 @@ install.sh_usage() {
|
||||
printf " install.sh --version | -v\n"
|
||||
echo
|
||||
|
||||
if [[ -n "$long_usage" ]]; then
|
||||
if [[ -n $long_usage ]]; then
|
||||
printf "%s\n" "Options:"
|
||||
|
||||
printf " %s\n" "--no-call, -n"
|
||||
@@ -165,13 +183,13 @@ install.sh_usage() {
|
||||
|
||||
printf " %s\n" "SOURCE"
|
||||
printf " Package source that should be used\n"
|
||||
printf " %s\n" "Allowed: stable, master, main"
|
||||
printf " %s\n" "Default: stable"
|
||||
printf " Allowed: stable, master, main\n"
|
||||
printf " Default: stable\n"
|
||||
echo
|
||||
|
||||
printf " %s\n" "PUBLISHER"
|
||||
printf " Publisher that should be used\n"
|
||||
printf " %s\n" "Default: inventree"
|
||||
printf " Default: inventree\n"
|
||||
echo
|
||||
|
||||
printf "%s\n" "Examples:"
|
||||
@@ -184,14 +202,11 @@ install.sh_usage() {
|
||||
}
|
||||
|
||||
normalize_input() {
|
||||
local arg passthru flags
|
||||
passthru=false
|
||||
local arg flags
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
arg="$1"
|
||||
if [[ $passthru == true ]]; then
|
||||
input+=("$arg")
|
||||
elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
|
||||
if [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then
|
||||
input+=("${BASH_REMATCH[1]}")
|
||||
input+=("${BASH_REMATCH[2]}")
|
||||
elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
|
||||
@@ -202,9 +217,6 @@ normalize_input() {
|
||||
for ((i = 0; i < ${#flags}; i++)); do
|
||||
input+=("-${flags:i:1}")
|
||||
done
|
||||
elif [[ "$arg" == "--" ]]; then
|
||||
passthru=true
|
||||
input+=("$arg")
|
||||
else
|
||||
input+=("$arg")
|
||||
fi
|
||||
@@ -213,11 +225,37 @@ normalize_input() {
|
||||
done
|
||||
}
|
||||
|
||||
inspect_args() {
|
||||
if ((${#args[@]})); then
|
||||
readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
|
||||
echo args:
|
||||
for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
|
||||
else
|
||||
echo args: none
|
||||
fi
|
||||
|
||||
if ((${#other_args[@]})); then
|
||||
echo
|
||||
echo other_args:
|
||||
echo "- \${other_args[*]} = ${other_args[*]}"
|
||||
for i in "${!other_args[@]}"; do
|
||||
echo "- \${other_args[$i]} = ${other_args[$i]}"
|
||||
done
|
||||
fi
|
||||
|
||||
if ((${#deps[@]})); then
|
||||
readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort)
|
||||
echo
|
||||
echo deps:
|
||||
for k in "${sorted_keys[@]}"; do echo "- \${deps[$k]} = ${deps[$k]}"; done
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
parse_requirements() {
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
key="$1"
|
||||
case "$key" in
|
||||
case "${1:-}" in
|
||||
--version | -v)
|
||||
version_command
|
||||
exit
|
||||
@@ -262,10 +300,11 @@ parse_requirements() {
|
||||
*)
|
||||
|
||||
if [[ -z ${args['source']+x} ]]; then
|
||||
|
||||
args['source']=$1
|
||||
shift
|
||||
|
||||
elif [[ -z ${args['publisher']+x} ]]; then
|
||||
|
||||
args['publisher']=$1
|
||||
shift
|
||||
else
|
||||
@@ -281,7 +320,7 @@ parse_requirements() {
|
||||
[[ -n ${args['source']:-} ]] || args['source']="stable"
|
||||
[[ -n ${args['publisher']:-} ]] || args['publisher']="inventree"
|
||||
|
||||
if [[ -n ${args['source']:-} ]] && [[ ! ${args['source']:-} =~ ^(stable|master|main)$ ]]; then
|
||||
if [[ -n ${args['source']} ]] && [[ ! ${args['source']} =~ ^(stable|master|main)$ ]]; then
|
||||
printf "%s\n" "source must be one of: stable, master, main" >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -289,19 +328,18 @@ parse_requirements() {
|
||||
}
|
||||
|
||||
initialize() {
|
||||
declare -g version="2.0"
|
||||
version="2.0"
|
||||
long_usage=''
|
||||
set -e
|
||||
|
||||
|
||||
}
|
||||
|
||||
run() {
|
||||
|
||||
declare -g long_usage=''
|
||||
declare -g -A args=()
|
||||
declare -g -A deps=()
|
||||
declare -g -a env_var_names=()
|
||||
declare -g -a input=()
|
||||
|
||||
declare -A args=()
|
||||
declare -A deps=()
|
||||
declare -a other_args=()
|
||||
declare -a input=()
|
||||
normalize_input "$@"
|
||||
parse_requirements "${input[@]}"
|
||||
|
||||
@@ -310,6 +348,5 @@ run() {
|
||||
esac
|
||||
}
|
||||
|
||||
command_line_args=("$@")
|
||||
initialize
|
||||
run "${command_line_args[@]}"
|
||||
run "$@"
|
||||
|
||||
@@ -5,7 +5,7 @@ publisher=${args[publisher]}
|
||||
no_call=${args[--no-call]}
|
||||
dry_run=${args[--dry-run]}
|
||||
|
||||
REQS="wget apt-transport-https curl gpg"
|
||||
REQS="wget apt-transport-https"
|
||||
|
||||
function do_call() {
|
||||
if [[ $dry_run ]]; then
|
||||
@@ -46,16 +46,17 @@ echo "### Installer for InvenTree - source: $publisher/$source_url"
|
||||
get_distribution
|
||||
echo "### Detected distribution: $OS $VER"
|
||||
SUPPORTED=true # is this OS supported?
|
||||
NEEDS_LIBSSL1_1=false # does this OS need libssl1.1?
|
||||
|
||||
DIST_OS=${OS,,}
|
||||
DIST_VER=$VER
|
||||
|
||||
case "$OS" in
|
||||
Ubuntu)
|
||||
if [[ $VER == "24.04" ]]; then
|
||||
SUPPORTED=true
|
||||
elif [[ $VER == "22.04" ]]; then
|
||||
if [[ $VER == "22.04" ]]; then
|
||||
SUPPORTED=true
|
||||
NEEDS_LIBSSL1_1=true
|
||||
DIST_VER="20.04"
|
||||
elif [[ $VER == "20.04" ]]; then
|
||||
SUPPORTED=true
|
||||
else
|
||||
@@ -99,6 +100,15 @@ for pkg in $REQS; do
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $NEEDS_LIBSSL1_1 == "true" ]]; then
|
||||
echo "### Installing libssl1.1"
|
||||
|
||||
echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list
|
||||
do_call "sudo apt-get update"
|
||||
do_call "sudo apt-get install libssl1.1"
|
||||
sudo rm /etc/apt/sources.list.d/focal-security.list
|
||||
fi
|
||||
|
||||
echo "### Getting and adding key"
|
||||
curl -fsSL https://dl.packager.io/srv/$publisher/InvenTree/key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/pkgr-inventree.gpg > /dev/null
|
||||
echo "### Adding package source"
|
||||
|
||||
@@ -5,40 +5,33 @@
|
||||
|
||||
set -eu
|
||||
|
||||
# The sha is the second element in APP_PKG_ITERATION
|
||||
VERSION="$APP_PKG_VERSION-$APP_PKG_ITERATION"
|
||||
echo "Setting VERSION information to $VERSION"
|
||||
echo "$VERSION" > VERSION
|
||||
|
||||
# The sha is the second element in APP_PKG_ITERATION
|
||||
SHA=$(echo $APP_PKG_ITERATION | cut -d'.' -f2)
|
||||
|
||||
# Download info
|
||||
echo "INFO collection | Getting info from github for commit $SHA"
|
||||
curl -L -s -f \
|
||||
echo "Getting info from github for commit $SHA"
|
||||
curl -L \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/$APP_REPO/commits/$SHA > commit.json
|
||||
echo "INFO collection | Got commit.json with size $(wc -c commit.json)"
|
||||
curl -L -s -f \
|
||||
https://api.github.com/repos/InvenTree/InvenTree/commits/$SHA > commit.json
|
||||
curl -L \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/$APP_REPO/commits/$SHA/branches-where-head > branches.json
|
||||
echo "INFO collection | Got branches.json with size $(wc -c branches.json)"
|
||||
curl -L -s -f \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/$APP_REPO/commits/$APP_PKG_VERSION > tag.json
|
||||
echo "INFO collection | Got tag.json with size $(wc -c tag.json)"
|
||||
https://api.github.com/repos/InvenTree/InvenTree/commits/$SHA/branches-where-head > branches.json
|
||||
|
||||
# Extract info
|
||||
echo "INFO extract | Extracting info from github"
|
||||
echo "Extracting info from github"
|
||||
DATE=$(jq -r '.commit.committer.date' commit.json)
|
||||
BRANCH=$(jq -r '.[].name' branches.json)
|
||||
NODE_ID=$(jq -r '.node_id' commit.json)
|
||||
SIGNATURE=$(jq -r '.commit.verification.signature' commit.json)
|
||||
FULL_SHA=$(jq -r '.sha' commit.json)
|
||||
|
||||
echo "INFO write | Write VERSION information"
|
||||
echo "$VERSION" > VERSION
|
||||
echo "Write VERSION information"
|
||||
echo "INVENTREE_COMMIT_HASH='$SHA'" >> VERSION
|
||||
echo "INVENTREE_COMMIT_SHA='$FULL_SHA'" >> VERSION
|
||||
echo "INVENTREE_COMMIT_DATE='$DATE'" >> VERSION
|
||||
echo "INVENTREE_PKG_INSTALLER='PKG'" >> VERSION
|
||||
echo "INVENTREE_PKG_BRANCH='$BRANCH'" >> VERSION
|
||||
@@ -46,22 +39,5 @@ echo "INVENTREE_PKG_TARGET='$TARGET'" >> VERSION
|
||||
echo "NODE_ID='$NODE_ID'" >> VERSION
|
||||
echo "SIGNATURE='$SIGNATURE'" >> VERSION
|
||||
|
||||
echo "INFO write | Written VERSION information"
|
||||
echo "### VERSION ###"
|
||||
echo "Written VERSION information"
|
||||
cat VERSION
|
||||
echo "### VERSION ###"
|
||||
|
||||
# Try to get frontend
|
||||
echo "INFO frontend | Trying to get frontend"
|
||||
# Check if tag sha is the same as the commit sha
|
||||
TAG_SHA=$(jq -r '.sha' tag.json)
|
||||
if [ "$TAG_SHA" != "$FULL_SHA" ]; then
|
||||
echo "INFO frontend | Tag sha '$TAG_SHA' is not the same as commit sha $FULL_SHA, can not download frontend"
|
||||
else
|
||||
echo "INFO frontend | Getting frontend from github via tag"
|
||||
curl https://github.com/$APP_REPO/releases/download/$APP_PKG_VERSION/frontend-build.zip -L -O -f
|
||||
mkdir -p src/backend/InvenTree/web/static
|
||||
echo "INFO frontend | Unzipping frontend"
|
||||
unzip -qq frontend-build.zip -d src/backend/InvenTree/web/static/web
|
||||
echo "INFO frontend | Unzipped frontend"
|
||||
fi
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
#
|
||||
# packager.io postinstall script functions
|
||||
#
|
||||
Color_Off='\033[0m'
|
||||
On_Red='\033[41m'
|
||||
PYTHON_FROM=9
|
||||
PYTHON_TO=14
|
||||
|
||||
function detect_docker() {
|
||||
if [ -n "$(grep docker </proc/1/cgroup)" ]; then
|
||||
@@ -13,7 +9,6 @@ function detect_docker() {
|
||||
else
|
||||
DOCKER="no"
|
||||
fi
|
||||
echo "# POI04| Running in docker: ${DOCKER}"
|
||||
}
|
||||
|
||||
function detect_initcmd() {
|
||||
@@ -31,7 +26,6 @@ function detect_initcmd() {
|
||||
if [ "${DOCKER}" == "yes" ]; then
|
||||
INIT_CMD="initctl"
|
||||
fi
|
||||
echo "# POI05| Using init command: ${INIT_CMD}"
|
||||
}
|
||||
|
||||
function detect_ip() {
|
||||
@@ -39,52 +33,27 @@ function detect_ip() {
|
||||
|
||||
if [ "${SETUP_NO_CALLS}" == "true" ]; then
|
||||
# Use local IP address
|
||||
echo "# POI06| Getting the IP address of the first local IP address"
|
||||
echo "# Getting the IP address of the first local IP address"
|
||||
export INVENTREE_IP=$(hostname -I | awk '{print $1}')
|
||||
else
|
||||
# Use web service to get the IP address
|
||||
echo "# POI06| Getting the IP address of the server via web service"
|
||||
echo "# Getting the IP address of the server via web service"
|
||||
export INVENTREE_IP=$(curl -s https://checkip.amazonaws.com)
|
||||
fi
|
||||
|
||||
echo "# POI06| IP address is ${INVENTREE_IP}"
|
||||
echo "IP address is ${INVENTREE_IP}"
|
||||
}
|
||||
|
||||
function detect_python() {
|
||||
# Detect if there is already a python version installed in /opt/inventree/env/lib
|
||||
if test -f "${APP_HOME}/env/bin/python"; then
|
||||
echo "# POI07| Python environment already present"
|
||||
echo "# Python environment already present"
|
||||
# Extract earliest python version initialised from /opt/inventree/env/lib
|
||||
SETUP_PYTHON=$(ls -1 ${APP_HOME}/env/bin/python* | sort | head -n 1)
|
||||
echo "# POI07| Found earlier used version: ${SETUP_PYTHON}"
|
||||
echo "# Found earliest version: ${SETUP_PYTHON}"
|
||||
else
|
||||
echo "# POI07| No python environment found - using environment variable: ${SETUP_PYTHON}"
|
||||
echo "# No python environment found - using ${SETUP_PYTHON}"
|
||||
fi
|
||||
|
||||
# Try to detect a python between 3.9 and 3.12 in reverse order
|
||||
if [ -z "$(which ${SETUP_PYTHON})" ]; then
|
||||
echo "# POI07| Trying to detecting python3.${PYTHON_FROM} to python3.${PYTHON_TO} - using newest version"
|
||||
for i in $(seq $PYTHON_TO -1 $PYTHON_FROM); do
|
||||
echo "# POI07| Checking for python3.${i}"
|
||||
if [ -n "$(which python3.${i})" ]; then
|
||||
SETUP_PYTHON="python3.${i}"
|
||||
echo "# POI07| Found python3.${i} installed - using for setup ${SETUP_PYTHON}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Ensure python can be executed - abort if not
|
||||
if [ -z "$(which ${SETUP_PYTHON})" ]; then
|
||||
echo "${On_Red}"
|
||||
echo "# POI07| Python ${SETUP_PYTHON} not found - aborting!"
|
||||
echo "# POI07| Please ensure python can be executed with the command '$SETUP_PYTHON' by the current user '$USER'."
|
||||
echo "# POI07| If you are using a different python version, please set the environment variable SETUP_PYTHON to the correct command - eg. 'python3.10'."
|
||||
echo "${Color_Off}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "# POI07| Using python command: ${SETUP_PYTHON}"
|
||||
}
|
||||
|
||||
function get_env() {
|
||||
@@ -99,7 +68,7 @@ function get_env() {
|
||||
done
|
||||
|
||||
if [ -n "${SETUP_DEBUG}" ]; then
|
||||
echo "# POI02| Done getting env $envname: ${!envname}"
|
||||
echo "Done getting env $envname: ${!envname}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -107,7 +76,7 @@ function detect_local_env() {
|
||||
# Get all possible envs for the install
|
||||
|
||||
if [ -n "${SETUP_DEBUG}" ]; then
|
||||
echo "# POI02| Printing local envs - before #++#"
|
||||
echo "# Printing local envs - before #++#"
|
||||
printenv
|
||||
fi
|
||||
|
||||
@@ -117,72 +86,46 @@ function detect_local_env() {
|
||||
done
|
||||
|
||||
if [ -n "${SETUP_DEBUG}" ]; then
|
||||
echo "# POI02| Printing local envs - after #++#"
|
||||
echo "# Printing local envs - after #++#"
|
||||
printenv
|
||||
fi
|
||||
|
||||
# Print branch and dir from VERSION file
|
||||
if [ -f "${APP_HOME}/VERSION" ]; then
|
||||
echo "# POI02| Loading environment variables from VERSION file"
|
||||
content=$(cat "${APP_HOME}/VERSION")
|
||||
# use grep to get the branch and target
|
||||
INVENTREE_PKG_BRANCH=($(echo $content | grep -oP 'INVENTREE_PKG_BRANCH=\K[^ ]+'))
|
||||
INVENTREE_PKG_TARGET=($(echo $content | grep -oP 'INVENTREE_PKG_TARGET=\K[^ ]+'))
|
||||
echo "Running in a package environment build on branch $INVENTREE_PKG_BRANCH for target $INVENTREE_PKG_TARGET"
|
||||
else
|
||||
echo "# POI02| VERSION file not found"
|
||||
fi
|
||||
}
|
||||
|
||||
function detect_envs() {
|
||||
# Detect all envs that should be passed to setup commands
|
||||
|
||||
echo "# POI03| Setting base environment variables"
|
||||
echo "# Setting base environment variables"
|
||||
|
||||
export INVENTREE_CONFIG_FILE=${INVENTREE_CONFIG_FILE:-${CONF_DIR}/config.yaml}
|
||||
|
||||
if test -f "${INVENTREE_CONFIG_FILE}"; then
|
||||
echo "# POI03| Using existing config file: ${INVENTREE_CONFIG_FILE}"
|
||||
echo "# Using existing config file: ${INVENTREE_CONFIG_FILE}"
|
||||
|
||||
# Install parser
|
||||
echo "# POI03| Installing requirements"
|
||||
pip install --require-hashes -r ${APP_HOME}/contrib/dev_reqs/requirements.txt -q
|
||||
echo "# POI03| Installed requirements"
|
||||
|
||||
# Load config
|
||||
export INVENTREE_CONF_DATA=$(cat ${INVENTREE_CONFIG_FILE} | jc --yaml)
|
||||
local CONF=$(cat ${INVENTREE_CONFIG_FILE} | jc --yaml)
|
||||
|
||||
# Parse the config file
|
||||
export INVENTREE_MEDIA_ROOT=$(jq -r '.[].media_root' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_STATIC_ROOT=$(jq -r '.[].static_root' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_BACKUP_DIR=$(jq -r '.[].backup_dir' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_PLUGINS_ENABLED=$(jq -r '.[].plugins_enabled' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_PLUGIN_FILE=$(jq -r '.[].plugin_file' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_SECRET_KEY_FILE=$(jq -r '.[].secret_key_file' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_MEDIA_ROOT=$(jq -r '.[].media_root' <<< ${CONF})
|
||||
export INVENTREE_STATIC_ROOT=$(jq -r '.[].static_root' <<< ${CONF})
|
||||
export INVENTREE_BACKUP_DIR=$(jq -r '.[].backup_dir' <<< ${CONF})
|
||||
export INVENTREE_PLUGINS_ENABLED=$(jq -r '.[].plugins_enabled' <<< ${CONF})
|
||||
export INVENTREE_PLUGIN_FILE=$(jq -r '.[].plugin_file' <<< ${CONF})
|
||||
export INVENTREE_SECRET_KEY_FILE=$(jq -r '.[].secret_key_file' <<< ${CONF})
|
||||
|
||||
export INVENTREE_DB_ENGINE=$(jq -r '.[].database.ENGINE' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_DB_NAME=$(jq -r '.[].database.NAME' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_DB_USER=$(jq -r '.[].database.USER' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_DB_PASSWORD=$(jq -r '.[].database.PASSWORD' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_DB_HOST=$(jq -r '.[].database.HOST' <<< ${INVENTREE_CONF_DATA})
|
||||
export INVENTREE_DB_PORT=$(jq -r '.[].database.PORT' <<< ${INVENTREE_CONF_DATA})
|
||||
|
||||
# Parse site URL if not already set
|
||||
if [ -z "${INVENTREE_SITE_URL}" ]; then
|
||||
# Try to read out the app config
|
||||
if [ -n "$(inventree config:get INVENTREE_SITE_URL)" ]; then
|
||||
echo "# POI03| Getting site URL from app config"
|
||||
export INVENTREE_SITE_URL=$(inventree config:get INVENTREE_SITE_URL)
|
||||
else
|
||||
echo "# POI03| Getting site URL from config file"
|
||||
export INVENTREE_SITE_URL=$(jq -r '.[].site_url' <<< ${INVENTREE_CONF_DATA})
|
||||
fi
|
||||
fi
|
||||
export INVENTREE_DB_ENGINE=$(jq -r '.[].database.ENGINE' <<< ${CONF})
|
||||
export INVENTREE_DB_NAME=$(jq -r '.[].database.NAME' <<< ${CONF})
|
||||
export INVENTREE_DB_USER=$(jq -r '.[].database.USER' <<< ${CONF})
|
||||
export INVENTREE_DB_PASSWORD=$(jq -r '.[].database.PASSWORD' <<< ${CONF})
|
||||
export INVENTREE_DB_HOST=$(jq -r '.[].database.HOST' <<< ${CONF})
|
||||
export INVENTREE_DB_PORT=$(jq -r '.[].database.PORT' <<< ${CONF})
|
||||
else
|
||||
echo "# POI03| No config file found: ${INVENTREE_CONFIG_FILE}, using envs or defaults"
|
||||
echo "# No config file found: ${INVENTREE_CONFIG_FILE}, using envs or defaults"
|
||||
|
||||
if [ -n "${SETUP_DEBUG}" ]; then
|
||||
echo "# POI03| Print current envs"
|
||||
echo "# Print current envs"
|
||||
printenv | grep INVENTREE_
|
||||
printenv | grep SETUP_
|
||||
fi
|
||||
@@ -193,7 +136,6 @@ function detect_envs() {
|
||||
export INVENTREE_PLUGINS_ENABLED=true
|
||||
export INVENTREE_PLUGIN_FILE=${CONF_DIR}/plugins.txt
|
||||
export INVENTREE_SECRET_KEY_FILE=${CONF_DIR}/secret_key.txt
|
||||
export INVENTREE_OIDC_PRIVATE_KEY_FILE=${CONF_DIR}/oidc.pem
|
||||
|
||||
export INVENTREE_DB_ENGINE=${INVENTREE_DB_ENGINE:-sqlite3}
|
||||
export INVENTREE_DB_NAME=${INVENTREE_DB_NAME:-${DATA_DIR}/database.sqlite3}
|
||||
@@ -202,50 +144,47 @@ function detect_envs() {
|
||||
export INVENTREE_DB_HOST=${INVENTREE_DB_HOST:-samplehost}
|
||||
export INVENTREE_DB_PORT=${INVENTREE_DB_PORT:-123456}
|
||||
|
||||
export INVENTREE_SITE_URL=${INVENTREE_SITE_URL:-http://${INVENTREE_IP}}
|
||||
|
||||
export SETUP_CONF_LOADED=true
|
||||
fi
|
||||
|
||||
# For debugging pass out the envs
|
||||
echo "# POI03| Collected environment variables:"
|
||||
echo "# POI03| INVENTREE_MEDIA_ROOT=${INVENTREE_MEDIA_ROOT}"
|
||||
echo "# POI03| INVENTREE_STATIC_ROOT=${INVENTREE_STATIC_ROOT}"
|
||||
echo "# POI03| INVENTREE_BACKUP_DIR=${INVENTREE_BACKUP_DIR}"
|
||||
echo "# POI03| INVENTREE_PLUGINS_ENABLED=${INVENTREE_PLUGINS_ENABLED}"
|
||||
echo "# POI03| INVENTREE_PLUGIN_FILE=${INVENTREE_PLUGIN_FILE}"
|
||||
echo "# POI03| INVENTREE_SECRET_KEY_FILE=${INVENTREE_SECRET_KEY_FILE}"
|
||||
echo "# POI03| INVENTREE_DB_ENGINE=${INVENTREE_DB_ENGINE}"
|
||||
echo "# POI03| INVENTREE_DB_NAME=${INVENTREE_DB_NAME}"
|
||||
echo "# POI03| INVENTREE_DB_USER=${INVENTREE_DB_USER}"
|
||||
echo "# Collected environment variables:"
|
||||
echo "# INVENTREE_MEDIA_ROOT=${INVENTREE_MEDIA_ROOT}"
|
||||
echo "# INVENTREE_STATIC_ROOT=${INVENTREE_STATIC_ROOT}"
|
||||
echo "# INVENTREE_BACKUP_DIR=${INVENTREE_BACKUP_DIR}"
|
||||
echo "# INVENTREE_PLUGINS_ENABLED=${INVENTREE_PLUGINS_ENABLED}"
|
||||
echo "# INVENTREE_PLUGIN_FILE=${INVENTREE_PLUGIN_FILE}"
|
||||
echo "# INVENTREE_SECRET_KEY_FILE=${INVENTREE_SECRET_KEY_FILE}"
|
||||
echo "# INVENTREE_DB_ENGINE=${INVENTREE_DB_ENGINE}"
|
||||
echo "# INVENTREE_DB_NAME=${INVENTREE_DB_NAME}"
|
||||
echo "# INVENTREE_DB_USER=${INVENTREE_DB_USER}"
|
||||
if [ -n "${SETUP_DEBUG}" ]; then
|
||||
echo "# POI03| INVENTREE_DB_PASSWORD=${INVENTREE_DB_PASSWORD}"
|
||||
echo "# INVENTREE_DB_PASSWORD=${INVENTREE_DB_PASSWORD}"
|
||||
fi
|
||||
echo "# POI03| INVENTREE_DB_HOST=${INVENTREE_DB_HOST}"
|
||||
echo "# POI03| INVENTREE_DB_PORT=${INVENTREE_DB_PORT}"
|
||||
echo "# POI03| INVENTREE_SITE_URL=${INVENTREE_SITE_URL}"
|
||||
echo "# INVENTREE_DB_HOST=${INVENTREE_DB_HOST}"
|
||||
echo "# INVENTREE_DB_PORT=${INVENTREE_DB_PORT}"
|
||||
}
|
||||
|
||||
function create_initscripts() {
|
||||
|
||||
# Make sure python env exists
|
||||
if test -f "${APP_HOME}/env"; then
|
||||
echo "# POI09| python environment already present - skipping"
|
||||
echo "# python environment already present - skipping"
|
||||
else
|
||||
echo "# POI09| Setting up python environment"
|
||||
echo "# Setting up python environment"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && ${SETUP_PYTHON} -m venv env"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && env/bin/pip install invoke wheel"
|
||||
|
||||
# Check INSTALLER_EXTRA exists and load it
|
||||
if test -f "${APP_HOME}/INSTALLER_EXTRA"; then
|
||||
echo "# POI09| Loading extra packages from INSTALLER_EXTRA"
|
||||
echo "# Loading extra packages from INSTALLER_EXTRA"
|
||||
source ${APP_HOME}/INSTALLER_EXTRA
|
||||
fi
|
||||
|
||||
if [ -n "${SETUP_EXTRA_PIP}" ]; then
|
||||
echo "# POI09| Installing extra pip packages"
|
||||
echo "# Installing extra pip packages"
|
||||
if [ -n "${SETUP_DEBUG}" ]; then
|
||||
echo "# POI09| Extra pip packages: ${SETUP_EXTRA_PIP}"
|
||||
echo "# Extra pip packages: ${SETUP_EXTRA_PIP}"
|
||||
fi
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && env/bin/pip install ${SETUP_EXTRA_PIP}"
|
||||
# Write extra packages to INSTALLER_EXTRA
|
||||
@@ -255,45 +194,37 @@ function create_initscripts() {
|
||||
|
||||
# Unlink default config if it exists
|
||||
if test -f "/etc/nginx/sites-enabled/default"; then
|
||||
echo "# POI09| Unlinking default nginx config\n# POI09| Old file still in /etc/nginx/sites-available/default"
|
||||
echo "# Unlinking default nginx config\n# Old file still in /etc/nginx/sites-available/default"
|
||||
sudo unlink /etc/nginx/sites-enabled/default
|
||||
echo "# POI09| Unlinked default nginx config"
|
||||
fi
|
||||
|
||||
# Create InvenTree specific nginx config
|
||||
echo "# POI09| Stopping nginx"
|
||||
echo "# Stopping nginx"
|
||||
${INIT_CMD} stop nginx
|
||||
echo "# POI09| Stopped nginx"
|
||||
echo "# POI09| Setting up nginx to ${SETUP_NGINX_FILE}"
|
||||
echo "# Setting up nginx to ${SETUP_NGINX_FILE}"
|
||||
# Always use the latest nginx config; important if new headers are added / needed for security
|
||||
cp ${APP_HOME}/contrib/packager.io/nginx.prod.conf ${SETUP_NGINX_FILE}
|
||||
sed -i s/inventree-server:8000/localhost:6000/g ${SETUP_NGINX_FILE}
|
||||
sed -i s=var/www=opt/inventree/data=g ${SETUP_NGINX_FILE}
|
||||
# Start nginx
|
||||
echo "# POI09| Starting nginx"
|
||||
echo "# Starting nginx"
|
||||
${INIT_CMD} start nginx
|
||||
echo "# POI09| Started nginx"
|
||||
|
||||
echo "# POI09| (Re)creating init scripts"
|
||||
echo "# (Re)creating init scripts"
|
||||
# This resets scale parameters to a known state
|
||||
inventree scale web="1" worker="1"
|
||||
|
||||
echo "# POI09| Enabling InvenTree on boot"
|
||||
echo "# Enabling InvenTree on boot"
|
||||
${INIT_CMD} enable inventree
|
||||
echo "# POI09| Enabled InvenTree on boot"
|
||||
}
|
||||
|
||||
function create_admin() {
|
||||
# Create data for admin users - stop with setting SETUP_ADMIN_NOCREATION to true
|
||||
if [ "${SETUP_ADMIN_NOCREATION}" == "true" ]; then
|
||||
echo "# POI10| Admin creation is disabled - skipping"
|
||||
return
|
||||
fi
|
||||
# Create data for admin user
|
||||
|
||||
if test -f "${SETUP_ADMIN_PASSWORD_FILE}"; then
|
||||
echo "# POI10| Admin data already exists - skipping"
|
||||
echo "# Admin data already exists - skipping"
|
||||
else
|
||||
echo "# POI10| Creating admin user data"
|
||||
echo "# Creating admin user data"
|
||||
|
||||
# Static admin data
|
||||
export INVENTREE_ADMIN_USER=${INVENTREE_ADMIN_USER:-admin}
|
||||
@@ -308,41 +239,38 @@ function create_admin() {
|
||||
}
|
||||
|
||||
function start_inventree() {
|
||||
echo "# POI15| Starting InvenTree"
|
||||
echo "# Starting InvenTree"
|
||||
${INIT_CMD} start inventree
|
||||
echo "# POI15| Started InvenTree"
|
||||
}
|
||||
|
||||
function stop_inventree() {
|
||||
echo "# POI11| Stopping InvenTree"
|
||||
echo "# Stopping InvenTree"
|
||||
${INIT_CMD} stop inventree
|
||||
echo "# POI11| Stopped InvenTree"
|
||||
}
|
||||
|
||||
function update_or_install() {
|
||||
set -e
|
||||
|
||||
# Set permissions so app user can write there
|
||||
chown ${APP_USER}:${APP_GROUP} ${APP_HOME} -R
|
||||
|
||||
# Run update as app user
|
||||
echo "# POI12| Updating InvenTree"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && pip install wheel python-dotenv"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && set -e && invoke update | sed -e 's/^/# POI12| u | /;'"
|
||||
echo "# Updating InvenTree"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && pip install wheel"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && invoke update | sed -e 's/^/# inv update| /;'"
|
||||
|
||||
# Make sure permissions are correct again
|
||||
echo "# POI12| Set permissions for data dir and media: ${DATA_DIR}"
|
||||
echo "# Set permissions for data dir and media: ${DATA_DIR}"
|
||||
chown ${APP_USER}:${APP_GROUP} ${DATA_DIR} -R
|
||||
chown ${APP_USER}:${APP_GROUP} ${CONF_DIR} -R
|
||||
}
|
||||
|
||||
function set_env() {
|
||||
echo "# POI13| Setting up InvenTree config values"
|
||||
echo "# Setting up InvenTree config values"
|
||||
|
||||
inventree config:set INVENTREE_CONFIG_FILE=${INVENTREE_CONFIG_FILE}
|
||||
|
||||
# Changing the config file
|
||||
echo "# POI13| Writing the settings to the config file ${INVENTREE_CONFIG_FILE}"
|
||||
echo "# Writing the settings to the config file ${INVENTREE_CONFIG_FILE}"
|
||||
# Media Root
|
||||
sed -i s=#media_root:\ \'/home/inventree/data/media\'=media_root:\ \'${INVENTREE_MEDIA_ROOT}\'=g ${INVENTREE_CONFIG_FILE}
|
||||
# Static Root
|
||||
@@ -355,108 +283,48 @@ function set_env() {
|
||||
sed -i s=#plugin_file:\ \'/path/to/plugins.txt\'=plugin_file:\ \'${INVENTREE_PLUGIN_FILE}\'=g ${INVENTREE_CONFIG_FILE}
|
||||
# Secret key file
|
||||
sed -i s=#secret_key_file:\ \'/etc/inventree/secret_key.txt\'=secret_key_file:\ \'${INVENTREE_SECRET_KEY_FILE}\'=g ${INVENTREE_CONFIG_FILE}
|
||||
# OIDC private key file
|
||||
sed -i s=#oidc_private_key_file:\ \'/etc/inventree/oidc.pem\'=oidc_private_key_file:\ \'${INVENTREE_OIDC_PRIVATE_KEY_FILE}\'=g ${INVENTREE_CONFIG_FILE}
|
||||
# Debug mode
|
||||
sed -i s=debug:\ True=debug:\ False=g ${INVENTREE_CONFIG_FILE}
|
||||
|
||||
# Database engine
|
||||
sed -i s=#\ ENGINE:\ Database\ engine.\ Selection\ from:=ENGINE:\ ${INVENTREE_DB_ENGINE}=g ${INVENTREE_CONFIG_FILE}
|
||||
sed -i s=#ENGINE:\ sampleengine=ENGINE:\ ${INVENTREE_DB_ENGINE}=g ${INVENTREE_CONFIG_FILE}
|
||||
# Database name
|
||||
sed -i s=#\ NAME:\ Database\ name=NAME:\ \'${INVENTREE_DB_NAME}\'=g ${INVENTREE_CONFIG_FILE}
|
||||
sed -i s=#NAME:\ \'/path/to/database\'=NAME:\ \'${INVENTREE_DB_NAME}\'=g ${INVENTREE_CONFIG_FILE}
|
||||
# Database user
|
||||
sed -i s=#\ USER:\ Database\ username\ \(if\ required\)=USER:\ ${INVENTREE_DB_USER}=g ${INVENTREE_CONFIG_FILE}
|
||||
sed -i s=#USER:\ sampleuser=USER:\ ${INVENTREE_DB_USER}=g ${INVENTREE_CONFIG_FILE}
|
||||
# Database password
|
||||
sed -i s=#\ PASSWORD:\ Database\ password\ \(if\ required\)=PASSWORD:\ ${INVENTREE_DB_PASSWORD}=g ${INVENTREE_CONFIG_FILE}
|
||||
sed -i s=#PASSWORD:\ samplepassword=PASSWORD:\ ${INVENTREE_DB_PASSWORD}=g ${INVENTREE_CONFIG_FILE}
|
||||
# Database host
|
||||
sed -i s=#\ HOST:\ Database\ host\ address\ \(if\ required\)=HOST:\ ${INVENTREE_DB_HOST}=g ${INVENTREE_CONFIG_FILE}
|
||||
sed -i s=#HOST:\ samplehost=HOST:\ ${INVENTREE_DB_HOST}=g ${INVENTREE_CONFIG_FILE}
|
||||
# Database port
|
||||
sed -i s=#\ PORT:\ Database\ host\ port\ \(if\ required\)=PORT:\ ${INVENTREE_DB_PORT}=g ${INVENTREE_CONFIG_FILE}
|
||||
sed -i s=#PORT:\ 123456=PORT:\ ${INVENTREE_DB_PORT}=g ${INVENTREE_CONFIG_FILE}
|
||||
|
||||
# Fixing the permissions
|
||||
chown ${APP_USER}:${APP_GROUP} ${DATA_DIR} ${INVENTREE_CONFIG_FILE}
|
||||
|
||||
echo "# POI13| Done setting up InvenTree config values"
|
||||
}
|
||||
|
||||
function set_site() {
|
||||
# Ensure IP is known
|
||||
if [ -z "${INVENTREE_IP}" ]; then
|
||||
echo "# POI14| No IP address found - skipping"
|
||||
echo "# No IP address found - skipping"
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if INVENTREE_SITE_URL in inventree config
|
||||
if [ -z "$(inventree config:get INVENTREE_SITE_URL)" ]; then
|
||||
# Prefer current INVENTREE_SITE_URL if set
|
||||
if [ -n "${INVENTREE_SITE_URL}" ]; then
|
||||
inventree config:set INVENTREE_SITE_URL=${INVENTREE_SITE_URL}
|
||||
else
|
||||
echo "# POI14| Setting up InvenTree site URL"
|
||||
inventree config:set INVENTREE_SITE_URL=http://${INVENTREE_IP}
|
||||
fi
|
||||
else
|
||||
echo "# POI14| Site URL already set to '$INVENTREE_SITE_URL' - skipping"
|
||||
echo "# Setting up InvenTree site URL"
|
||||
inventree config:set INVENTREE_SITE_URL=http://${INVENTREE_IP}
|
||||
fi
|
||||
}
|
||||
|
||||
function final_message() {
|
||||
echo "# POI16| Printing Final message"
|
||||
echo -e "####################################################################################"
|
||||
echo -e "This InvenTree install uses nginx, the settings for the webserver can be found in"
|
||||
echo -e "${SETUP_NGINX_FILE}"
|
||||
echo -e "Try opening InvenTree with any of \n${INVENTREE_SITE_URL} , http://localhost/ or http://${INVENTREE_IP}/ \n"
|
||||
# Print admin user data only if set
|
||||
if [ -n "${INVENTREE_ADMIN_USER}" ]; then
|
||||
echo -e "Admin user data:"
|
||||
echo -e " Email: ${INVENTREE_ADMIN_EMAIL}"
|
||||
echo -e " Username: ${INVENTREE_ADMIN_USER}"
|
||||
echo -e " Password: ${INVENTREE_ADMIN_PASSWORD}"
|
||||
else
|
||||
echo -e "No admin set during this operation - depending on the deployment method a admin user might have been created with an initial password saved in `$SETUP_ADMIN_PASSWORD_FILE`"
|
||||
fi
|
||||
echo -e "Try opening InvenTree with either\nhttp://localhost/ or http://${INVENTREE_IP}/\n"
|
||||
echo -e "Admin user data:"
|
||||
echo -e " Email: ${INVENTREE_ADMIN_EMAIL}"
|
||||
echo -e " Username: ${INVENTREE_ADMIN_USER}"
|
||||
echo -e " Password: ${INVENTREE_ADMIN_PASSWORD}"
|
||||
echo -e "####################################################################################"
|
||||
}
|
||||
|
||||
|
||||
function update_checks() {
|
||||
echo "# POI08| Running upgrade"
|
||||
local old_version=$1
|
||||
local old_version_rev=$(echo ${old_version} | cut -d'-' -f1 | cut -d'.' -f2)
|
||||
local new_version=$(dpkg-query --show --showformat='${Version}' inventree)
|
||||
local new_version_rev=$(echo ${new_version} | cut -d'-' -f1 | cut -d'.' -f2)
|
||||
echo "# POI08| Old version is: ${old_version} | ${old_version_rev} - updating to ${new_version} | ${old_version_rev}"
|
||||
|
||||
local ABORT=false
|
||||
function check_config_value() {
|
||||
local env_key=$1
|
||||
local config_key=$2
|
||||
local name=$3
|
||||
|
||||
local value=$(inventree config:get ${env_key})
|
||||
if [ -z "${value}" ] || [ "$value" == "null" ]; then
|
||||
value=$(jq -r ".[].${config_key}" <<< ${INVENTREE_CONF_DATA})
|
||||
fi
|
||||
if [ -z "${value}" ] || [ "$value" == "null" ]; then
|
||||
echo "# POI08| No setting for ${name} found - please set it manually either in ${INVENTREE_CONFIG_FILE} under '${config_key}' or with 'inventree config:set ${env_key}=value'"
|
||||
ABORT=true
|
||||
else
|
||||
echo "# POI08| Found setting for ${name} - ${value}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Custom checks if old version is below 0.8.0
|
||||
if [ "${old_version_rev}" -lt "9" ]; then
|
||||
echo "# POI08| Old version is below 0.9.0 - You might be missing some configs"
|
||||
|
||||
# Check for BACKUP_DIR and SITE_URL in INVENTREE_CONF_DATA and config
|
||||
check_config_value "INVENTREE_SITE_URL" "site_url" "site URL"
|
||||
check_config_value "INVENTREE_BACKUP_DIR" "backup_dir" "backup dir"
|
||||
|
||||
if [ "${ABORT}" = true ]; then
|
||||
echo "# POI08| Aborting - please set the missing values and run the update again"
|
||||
exit 1
|
||||
fi
|
||||
echo "# POI08| All checks passed - continuing with the update"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -3,18 +3,15 @@
|
||||
# packager.io postinstall script
|
||||
#
|
||||
|
||||
echo "# POI01| Running postinstall script - start - $(date)"
|
||||
exec > >(tee ${APP_HOME}/log/setup_$(date +"%F_%H_%M_%S").log) 2>&1
|
||||
|
||||
PATH=${APP_HOME}/env/bin:${APP_HOME}/:/sbin:/bin:/usr/sbin:/usr/bin:
|
||||
|
||||
# import functions
|
||||
echo "# POI01| Importing functions"
|
||||
. ${APP_HOME}/contrib/packager.io/functions.sh
|
||||
echo "# POI01| Functions imported"
|
||||
|
||||
# Envs that should be passed to setup commands
|
||||
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,INVENTREE_SITE_URL,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON,SETUP_ADMIN_NOCREATION
|
||||
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON
|
||||
|
||||
# Get the envs
|
||||
detect_local_env
|
||||
@@ -27,26 +24,17 @@ export SETUP_NGINX_FILE=${SETUP_NGINX_FILE:-/etc/nginx/sites-enabled/inventree.c
|
||||
export SETUP_ADMIN_PASSWORD_FILE=${CONF_DIR}/admin_password.txt
|
||||
export SETUP_NO_CALLS=${SETUP_NO_CALLS:-false}
|
||||
export SETUP_PYTHON=${SETUP_PYTHON:-python3.9}
|
||||
export SETUP_ADMIN_NOCREATION=${SETUP_ADMIN_NOCREATION:-false}
|
||||
# SETUP_DEBUG can be set to get debug info
|
||||
# SETUP_EXTRA_PIP can be set to install extra pip packages
|
||||
# SETUP_PYTHON can be set to use a different python version
|
||||
|
||||
# get base info
|
||||
detect_ip
|
||||
detect_envs
|
||||
detect_docker
|
||||
detect_initcmd
|
||||
detect_ip
|
||||
detect_python
|
||||
|
||||
# Check if we are updating and need to alert
|
||||
echo "# POI08| Checking if update checks are needed"
|
||||
if [ -z "$2" ]; then
|
||||
echo "# POI08| Normal install - no need for checks"
|
||||
else
|
||||
update_checks $2
|
||||
fi
|
||||
|
||||
# create processes
|
||||
create_initscripts
|
||||
create_admin
|
||||
@@ -63,4 +51,3 @@ start_inventree
|
||||
|
||||
# show info
|
||||
final_message
|
||||
echo "# POI17| Running postinstall script - done - $(date)"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# packager.io preinstall/preremove script
|
||||
#
|
||||
echo "# PRI01| Running preinstall script - start - $(date)"
|
||||
PATH=${APP_HOME}/env/bin:${APP_HOME}/:/sbin:/bin:/usr/sbin:/usr/bin:
|
||||
|
||||
# Envs that should be passed to setup commands
|
||||
export SETUP_ENVS=PATH,APP_HOME,INVENTREE_MEDIA_ROOT,INVENTREE_STATIC_ROOT,INVENTREE_BACKUP_DIR,INVENTREE_PLUGINS_ENABLED,INVENTREE_PLUGIN_FILE,INVENTREE_CONFIG_FILE,INVENTREE_SECRET_KEY_FILE,INVENTREE_DB_ENGINE,INVENTREE_DB_NAME,INVENTREE_DB_USER,INVENTREE_DB_PASSWORD,INVENTREE_DB_HOST,INVENTREE_DB_PORT,INVENTREE_ADMIN_USER,INVENTREE_ADMIN_EMAIL,INVENTREE_ADMIN_PASSWORD,INVENTREE_SITE_URL,SETUP_NGINX_FILE,SETUP_ADMIN_PASSWORD_FILE,SETUP_NO_CALLS,SETUP_DEBUG,SETUP_EXTRA_PIP,SETUP_PYTHON
|
||||
|
||||
if test -f "${APP_HOME}/env/bin/pip"; then
|
||||
# Check if clear-generated is available
|
||||
if sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && invoke int.clear-generated --help" > /dev/null 2>&1; then
|
||||
echo "# PRI02| Clearing precompiled files"
|
||||
sudo -u ${APP_USER} --preserve-env=$SETUP_ENVS bash -c "cd ${APP_HOME} && invoke int.clear-generated"
|
||||
else
|
||||
echo "# PRI02| Clearing precompiled files - skipping"
|
||||
fi
|
||||
else
|
||||
echo "# PRI02| No python environment found - skipping"
|
||||
fi
|
||||
|
||||
echo "# PRI03| Running preinstall script - done - $(date)"
|
||||
@@ -1,14 +1,8 @@
|
||||
# Configuration file for Crowdin project integration
|
||||
# See: https://crowdin.com/project/inventree
|
||||
|
||||
"commit_message": "Fix: New translations %original_file_name% from Crowdin"
|
||||
"append_commit_message": false
|
||||
"preserve_hierarchy": true
|
||||
|
||||
files:
|
||||
- source: /src/backend/InvenTree/locale/en/LC_MESSAGES/django.po
|
||||
dest: /%original_path%/%original_file_name%
|
||||
translation: /src/backend/InvenTree/locale/%two_letters_code%/LC_MESSAGES/%original_file_name%
|
||||
- source: /src/frontend/src/locales/en/messages.po
|
||||
dest: /%original_path%/%original_file_name%
|
||||
translation: /src/frontend/src/locales/%two_letters_code%/%original_file_name%
|
||||
|
||||
9
docs/.gitignore
vendored
@@ -13,17 +13,8 @@ site/
|
||||
# Generated API schema files
|
||||
docs/api/schema/*.yml
|
||||
|
||||
# Temporary cache files
|
||||
url_cache.txt
|
||||
invoke-commands.txt
|
||||
|
||||
# Temp files
|
||||
releases.json
|
||||
versions.json
|
||||
inventree_filters.yml
|
||||
inventree_settings.json
|
||||
observed_settings.json
|
||||
inventree_tags.yml
|
||||
|
||||
.vscode/
|
||||
generated/
|
||||
|
||||
@@ -59,24 +59,18 @@ Click [here](/part/views)
|
||||
|
||||
### Images
|
||||
|
||||
Images are served from the `./docs/assets/images` folder and can be added as follows:
|
||||
|
||||
Images are served from the `./docs/assets/images` folder and can be added as follow:
|
||||
```
|
||||
{{ image("image_name.png", base="subfolder", title="Image title") }}
|
||||
{% with id="image_id", url="folder/image_name.png", description="Text shown if image is not loaded properly" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
```
|
||||
|
||||
See the `image` macro in `./docs/main.py` for more information.
|
||||
|
||||
### Icons
|
||||
|
||||
Icons can be rendered (using the [tabler icon set](https://tabler.io/icons)) as follows:
|
||||
|
||||
```
|
||||
{{ icon("brand-github", color="red")}}
|
||||
```
|
||||
|
||||
See the `icon` macro in `./docs/main.py` for more information.
|
||||
|
||||
Replace:
|
||||
* `image_id` with a short unique identifier for the image (most commonly, `image_id` is same as `image_name`)
|
||||
* `folder` with the folder in `docs/assets/images` in which the image is stored
|
||||
* `image_name` with the name of the image
|
||||
* `.png` with the image extension (PNG or JPEG are preferred formats)
|
||||
|
||||
### Global variables
|
||||
|
||||
|
||||
5
docs/_includes/app_img.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{% set url = 'app/' + url %}
|
||||
|
||||
{% with id=id, url=url, maxheight="240px", description="" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
30
docs/_includes/img.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% if 'http' in url %}
|
||||
{% set img_url = url %}
|
||||
{% else %}
|
||||
{% set img_url = config.assets_dir + '/images/' + url %}
|
||||
{% endif %}
|
||||
|
||||
<figure class='image image-inventree'>
|
||||
{% if id %}
|
||||
<!-- The link that, when clicked, will display the image in full screen -->
|
||||
<a href="#{{ id }}">
|
||||
{% elif img_url %}
|
||||
<a href="{{ img_url }}">
|
||||
{% endif %}
|
||||
<img class='img-inline' src='{{ img_url }}' alt='{{ description }}' title='{{ description }}'
|
||||
{% if maxwidth or maxheight %}style='
|
||||
{% if maxwidth %} max-width:{{ maxwidth }};{% endif %}
|
||||
{% if maxheight %} max-height: {{ maxheight }};{% endif %}
|
||||
'{% endif %}
|
||||
>
|
||||
{% if id or img_url %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if id %}
|
||||
<!-- The full screen image, hidden by default -->
|
||||
<a href="#_" class="overlay" id="{{ id }}">
|
||||
<img src="{{ img_url }}" alt="{{ description }}" />
|
||||
</a>
|
||||
{% endif %}
|
||||
</figure>
|
||||
@@ -20,7 +20,8 @@
|
||||
<div class="md-grid md-typeset">
|
||||
<div class="mdx-hero"></div>
|
||||
<h1>
|
||||
<i class="ti ti-search"></i> Page not found
|
||||
<span class='fas fa-search'></span>
|
||||
Page not found
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
{{ page.content }}
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
@@ -15,8 +15,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2 id="intuitive-inventory-management">InvenTree - Intuitive Inventory Management</h2>
|
||||
|
||||
<!-- Hero for landing page -->
|
||||
<section class="mdx-container">
|
||||
<div class="md-grid md-typeset">
|
||||
@@ -26,24 +24,24 @@
|
||||
<div class="mdx-hero__content">
|
||||
|
||||
<a href="https://inventree.org" title="InvenTree Website" class="md-button">
|
||||
<i class='ti ti-world'></i> Website
|
||||
<span class='fas fa-globe'></span> Website
|
||||
</a>
|
||||
|
||||
<a href="start" title="Install InvenTree" class="md-button">
|
||||
<i class='ti ti-server-bolt'></i> Install
|
||||
<a href="start/intro" title="Install InvenTree" class="md-button">
|
||||
<span class='fas fa-server'></span> Install
|
||||
</a>
|
||||
<a href="app" title="InvenTree mobile app" class="md-button">
|
||||
<i class='ti ti-device-mobile'></i> Mobile App
|
||||
<a href="app/app" title="InvenTree mobile app" class="md-button">
|
||||
<span class='fas fa-mobile-alt'></span> Mobile App
|
||||
</a>
|
||||
<a href="https://crowdin.com/project/inventree" title="Help translate InvenTree" class="md-button">
|
||||
<i class='ti ti-language'></i> Translate
|
||||
<span class='fas fa-language'></span> Translate
|
||||
</a>
|
||||
<a href="https://github.com/inventree/inventree" title="Explore InvenTree source code" class="md-button md-button">
|
||||
<i class='ti ti-code-circle'></i> Source Code
|
||||
<span class='fab fa-github'></span> Source Code
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{ page.content }}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ icon("clipboard") }}</span> Release</th>
|
||||
<th>{{ icon("calendar") }} Date</th>
|
||||
<th>{{ icon("brand-github") }} GitHub</th>
|
||||
<th>{{ icon("brand-docker") }} Docker</th>
|
||||
<th><span class='fas fa-clipboard-list'></span> Release</th>
|
||||
<th><span class='fas fa-calendar-alt'></span> Date</th>
|
||||
<th><span class='fab fa-github'></span> GitHub</th>
|
||||
<th><span class='fab fa-docker'></span> Docker</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -10,7 +10,7 @@ tld = os.path.abspath(os.path.join(here, '..'))
|
||||
|
||||
config_file = os.path.join(tld, 'mkdocs.yml')
|
||||
|
||||
with open(config_file, encoding='utf-8') as f:
|
||||
with open(config_file, 'r') as f:
|
||||
data = yaml.load(f, yaml.BaseLoader)
|
||||
|
||||
assert data['strict'] == 'true'
|
||||
|
||||
121
docs/docs/api/api.md
Normal file
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: InvenTree API
|
||||
---
|
||||
|
||||
## InvenTree API
|
||||
|
||||
InvenTree provides a powerful REST API for interacting with inventory data on the server. Low-level data access and manipulation is available, with integrated user authentication and data validation.
|
||||
|
||||
!!! info "Django REST Framework"
|
||||
The InvenTree API is based on the powerful and flexible [Django REST Framework](https://www.django-rest-framework.org/).
|
||||
|
||||
## Documentation
|
||||
|
||||
The API is self-documenting, and the documentation is provided alongside any InvenTree installation instance. If (for example) you have an InvenTree instance running at `http://127.0.0.1:8000` then the API documentation is available at `http://127.0.0.1:8000/api-doc/`
|
||||
|
||||
{% with id="api_doc", url="api/api_doc.png", description="API documentation" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Schema Description
|
||||
The API schema is also documented in the [API Schema](./schema.md) page.
|
||||
|
||||
### Generating Schema File
|
||||
|
||||
If you want to generate the API schema file yourself (for example to use with an external client, use the `invoke schema` command. Run with the `-help` command to see available options.
|
||||
|
||||
```
|
||||
invoke schema -help
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
Users must be authenticated to gain access to the InvenTree API. The API accepts either basic username:password authentication, or token authentication. Token authentication is recommended as it provides much faster API access.
|
||||
|
||||
!!! warning "Permissions"
|
||||
API access is restricted based on the permissions assigned to the user.
|
||||
|
||||
### Basic Auth
|
||||
|
||||
Users can authenticate against the API using basic authentication - specifically a valid combination of `username` and `password` credentials.
|
||||
|
||||
### Tokens
|
||||
|
||||
Each user is assigned an authentication token which can be used to access the API. This token is persistent for that user (unless invalidated by an administrator) and can be used across multiple sessions.
|
||||
|
||||
!!! info "Token Administration"
|
||||
User tokens can be created and/or invalidated via the Admin interface.
|
||||
|
||||
### Requesting a Token
|
||||
|
||||
If a user does not know their access token, it can be requested via the API interface itself, using a basic authentication request.
|
||||
|
||||
To obtain a valid token, perform a GET request to `/api/user/token/`. No data are required, but a valid username / password combination must be supplied in the authentication headers.
|
||||
|
||||
!!! info "Credentials"
|
||||
Ensure that a valid username:password combination are supplied as basic authorization headers.
|
||||
|
||||
Once a valid token is received from the server, subsequent API requests should be performed using that token.
|
||||
|
||||
If the supplied user credentials are validated, the server will respond with:
|
||||
|
||||
```
|
||||
HTTP_200_OK
|
||||
{
|
||||
token: "usertokendatastring",
|
||||
}
|
||||
```
|
||||
|
||||
### Using a Token
|
||||
|
||||
After reception of a valid authentication token, it can be subsequently used to perform token-based authentication.
|
||||
|
||||
The token value sent to the server must be of the format `Token <TOKEN-VALUE>` (without the `<` and `>` characters).
|
||||
|
||||
**Example: Javascript**
|
||||
```javascript
|
||||
var token = "MY-TOKEN-VALUE-HERE";
|
||||
|
||||
$.ajax({
|
||||
url: "http://localhost:8080/api/part/",
|
||||
type: 'GET',
|
||||
headers: {"Authorization": `Token ${token}`}
|
||||
});
|
||||
```
|
||||
|
||||
**Example: Python (Requests)**
|
||||
```python
|
||||
import requests
|
||||
|
||||
token = 'MY-TOKEN-VALUE-HERE'
|
||||
data = { ... }
|
||||
headers = {
|
||||
'AUTHORIZATION': f'Token {token}'
|
||||
}
|
||||
response = request.get('http://localhost:8080/api/part/', data=data, headers=headers)
|
||||
```
|
||||
|
||||
## Authorization
|
||||
|
||||
### User Roles
|
||||
|
||||
Users can only perform REST API actions which align with their assigned [role permissions](../settings/permissions.md#roles).
|
||||
Once a user has *authenticated* via the API, a list of the available roles can be retrieved from:
|
||||
|
||||
`/api/user/roles/`
|
||||
|
||||
For example, when accessing the API from a *superuser* account:
|
||||
|
||||
{% with id="api_roles", url="api/api_roles.png", description="API superuser roles" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
Or, when accessing the API from an account which has read-only permissions:
|
||||
|
||||
{% with id="api_roles_2", url="api/api_roles_2.png", description="API user roles" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Permission Denied
|
||||
|
||||
If an API action outside of the user's role(s) is attempted, the server will respond with a 403 permission error message.
|
||||
@@ -4,7 +4,7 @@ title: Interactive API
|
||||
|
||||
## Interactive API
|
||||
|
||||
If the server is running in [Debug Mode](../start/index.md#debug-mode) then an interactive version of the API is available using a browser.
|
||||
If the server is running in [Debug Mode](../start/intro.md#debug-mode) then an interactive version of the API is available using a browser.
|
||||
|
||||
!!! info "Debug Mode"
|
||||
This interactive API is only available when running the server in debug mode
|
||||
@@ -16,16 +16,22 @@ If the server is running in [Debug Mode](../start/index.md#debug-mode) then an i
|
||||
|
||||
Various list endpoints can be displayed as shown below:
|
||||
|
||||
{{ image("api/api_browse.png", "List API") }}
|
||||
{% with id="api_browse", url="api/api_browse.png", description="List API" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Filtering
|
||||
|
||||
List views can be filtered interactively:
|
||||
|
||||
{{ image("api/api_filters.png", "Filter API") }}
|
||||
{% with id="api_filter", url="api/api_filters.png", description="Filter API" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Detail View
|
||||
|
||||
Detail view endpoints can also be displayed:
|
||||
|
||||
{{ image("api/api_detail.png", "Detail API") }}
|
||||
{% with id="api_detail", url="api/api_detail.png", description="Detail API" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -6,7 +6,7 @@ title: Bulk Deletion
|
||||
|
||||
While deleting items individually via the API is supported, it can prove inefficient (time consuming) when multiple items are to be deleted sequentially.
|
||||
|
||||
For example, if the user wishes to delete a large number items (such as lines from a [Bill of Materials](../manufacturing/bom.md)), these items are deleted sequentially, with each `DELETE` separate request requiring network transfer, database access, cleanup, etc.
|
||||
For example, if the user wishes to delete a large number items (such as lines from a [Bill of Materials](../build/bom.md)), these items are deleted sequentially, with each `DELETE` separate request requiring network transfer, database access, cleanup, etc.
|
||||
|
||||
A much more efficient approach is to allow for "bulk deletion" of multiple database items in a single transaction. This means that only one network request is required, and only a single database access request.
|
||||
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
---
|
||||
title: InvenTree API
|
||||
---
|
||||
|
||||
## InvenTree API
|
||||
|
||||
InvenTree provides a powerful REST API for interacting with inventory data on the server. Low-level data access and manipulation is available, with integrated user authentication and data validation.
|
||||
|
||||
!!! info "Django REST Framework"
|
||||
The InvenTree API is based on the powerful and flexible [Django REST Framework](https://www.django-rest-framework.org/).
|
||||
|
||||
## Documentation
|
||||
|
||||
The API is self-documenting, and the documentation is provided alongside any InvenTree installation instance. If (for example) you have an InvenTree instance running at `http://127.0.0.1:8000` then the API documentation is available at `http://127.0.0.1:8000/api-doc/`
|
||||
|
||||
{{ image("api/api_doc.png", "API documentation") }}
|
||||
|
||||
### Browseble API
|
||||
|
||||
If [debug mode](../start/index.md#debug-mode) is enabled, the API can be browsed directly from the web interface. This provides a simple way to explore the API and test out different endpoints. Simply navigate your web browser to any API endpoint, and the API will be displayed in a human-readable format.
|
||||
|
||||
### Schema Description
|
||||
|
||||
The API schema is also documented in the [API Schema](./schema.md) page.
|
||||
|
||||
### Generating Schema File
|
||||
|
||||
If you want to generate the API schema file yourself. For example, to use with an external client, use the `invoke dev.schema` command. Run with the `-help` command to see available options.
|
||||
|
||||
```
|
||||
invoke dev.schema -help
|
||||
```
|
||||
|
||||
|
||||
## Authentication
|
||||
|
||||
Users must be authenticated to gain access to the InvenTree API. The API accepts either basic username:password authentication, or token authentication. Token authentication is recommended as it provides much faster API access.
|
||||
|
||||
!!! warning "Permissions"
|
||||
API access is restricted based on the permissions assigned to the user or scope of the application.
|
||||
|
||||
### Basic Auth
|
||||
|
||||
Users can authenticate against the API using basic authentication - specifically a valid combination of `username` and `password` credentials.
|
||||
|
||||
### Tokens
|
||||
|
||||
Each user is assigned an authentication token which can be used to access the API. This token is persistent for that user (unless invalidated by an administrator) and can be used across multiple sessions.
|
||||
|
||||
!!! info "Token Administration"
|
||||
User tokens can be created and/or invalidated via the user settings, [Admin Center](../settings/admin.md#admin-center) or admin interface.
|
||||
|
||||
#### Requesting a Token
|
||||
|
||||
If a user does not know their access token, it can be requested via the API interface itself, using a basic authentication request.
|
||||
|
||||
To obtain a valid token, perform a GET request to `/api/user/token/`. No data are required, but a valid username / password combination must be supplied in the authentication headers.
|
||||
|
||||
!!! info "Credentials"
|
||||
Ensure that a valid username:password combination are supplied as basic authorization headers.
|
||||
|
||||
Once a valid token is received from the server, subsequent API requests should be performed using that token.
|
||||
|
||||
If the supplied user credentials are validated, the server will respond with:
|
||||
|
||||
```
|
||||
HTTP_200_OK
|
||||
{
|
||||
token: "usertokendatastring",
|
||||
}
|
||||
```
|
||||
|
||||
#### Using a Token
|
||||
|
||||
After reception of a valid authentication token, it can be subsequently used to perform token-based authentication.
|
||||
|
||||
The token value sent to the server must be of the format `Token <TOKEN-VALUE>` (without the `<` and `>` characters).
|
||||
|
||||
**Example: Javascript**
|
||||
```javascript
|
||||
var token = "MY-TOKEN-VALUE-HERE";
|
||||
|
||||
$.ajax({
|
||||
url: "http://localhost:8080/api/part/",
|
||||
type: 'GET',
|
||||
headers: {"Authorization": `Token ${token}`}
|
||||
});
|
||||
```
|
||||
|
||||
**Example: Python (Requests)**
|
||||
```python
|
||||
import requests
|
||||
|
||||
token = 'MY-TOKEN-VALUE-HERE'
|
||||
data = { ... }
|
||||
headers = {
|
||||
'AUTHORIZATION': f'Token {token}'
|
||||
}
|
||||
response = request.get('http://localhost:8080/api/part/', data=data, headers=headers)
|
||||
```
|
||||
|
||||
### oAuth2 and OIDC
|
||||
|
||||
!!! warning "Experimental"
|
||||
This is an experimental feature that needs to be specifically enabled. See [Experimental features](../settings/experimental.md) for more information.
|
||||
|
||||
InvenTree has built-in support for using [oAuth2](https://oauth.net/2/) and OpenID Connect (OIDC) for authentication to the API. This enables using the instance as a very limited identity provider.
|
||||
|
||||
A default application using a public client with PKCE enabled ships with each instance. Intended to be used with the python api and configured with very wide scopes this can also be used for quick tests - the cliend_id is `zDFnsiRheJIOKNx6aCQ0quBxECg1QBHtVFDPloJ6`.
|
||||
|
||||
#### Managing applications
|
||||
|
||||
Superusers can register new applications and manage existing ones using a small application under the subpath `/o/applications/`.
|
||||
It is recommended to:
|
||||
- read the spec (RFC 6749 / 6750) and/or best practices (RFC 9700) before choosing client types
|
||||
- chose scopes as narrow as possible
|
||||
- configure redirection URIs as exact as possible
|
||||
|
||||
#### Scopes
|
||||
|
||||
InvenTree's oAuth scopes are strongly related to the [user roles](#user-roles).
|
||||
Names consist of 1. type, 2. kind and 3. (opt) role, separated by colons.
|
||||
|
||||
|
||||
There are 3 types:
|
||||
|
||||
- a: administrative scopes - used for administrating the server - these can be staff or superuser scopes
|
||||
- g: general scopes - give wide access to the basic building blocks of InvenTree
|
||||
- r: role scopes - map to specific actions (2) and roles (3)
|
||||
|
||||
Examples:
|
||||
```bash
|
||||
a:superuser
|
||||
g:read
|
||||
r:change:part
|
||||
r:delete:stock
|
||||
```
|
||||
|
||||
!!! info "Read the API docs"
|
||||
The API [documentation](#documentation) and [schema](./schema.md) list the required scopes for every API endpoint / interaction in the security sections.
|
||||
|
||||
## Authorization
|
||||
|
||||
### User Roles
|
||||
|
||||
Users can only perform REST API actions which align with their assigned [role permissions](../settings/permissions.md#roles).
|
||||
Once a user has *authenticated* via the API, a list of the available roles can be retrieved from:
|
||||
|
||||
`/api/user/roles/`
|
||||
|
||||
For example, when accessing the API from a *superuser* account:
|
||||
|
||||
{{ image("api/api_roles.png", "API superuser roles") }}
|
||||
|
||||
Or, when accessing the API from an account which has read-only permissions:
|
||||
|
||||
{{ image("api/api_roles_2.png", "API user roles") }}
|
||||
|
||||
### Permission Denied
|
||||
|
||||
If an API action outside of the user's role(s) is attempted, the server will respond with a 403 permission error message.
|
||||
@@ -4,7 +4,7 @@ title: Model Metadata
|
||||
|
||||
## Model Metadata
|
||||
|
||||
The API is *self describing* in that it provides metadata about the various fields available at any given endpoint. External applications (such as the [python interface](../api/python/index.md)) can introspect the API to determine information about the model fields.
|
||||
The API is *self describing* in that it provides metadata about the various fields available at any given endpoint. External applications (such as the [python interface](../api/python/python.md)) can introspect the API to determine information about the model fields.
|
||||
|
||||
!!! tip "API Forms"
|
||||
The various forms implemented in the InvenTree web interface make heavy use of this metadata feature
|
||||
@@ -13,9 +13,11 @@ The API is *self describing* in that it provides metadata about the various fiel
|
||||
|
||||
To request metadata about a particular API endpoint, simply perform an `OPTIONS` method request against the API URL.
|
||||
|
||||
For example, to view the metadata available for creating a new [Part Category](../part/index.md#part-category), an `OPTIONS` request to `/api/part/category/` yields:
|
||||
For example, to view the metadata available for creating a new [Part Category](../part/part.md#part-category), an `OPTIONS` request to `/api/part/category/` yields:
|
||||
|
||||
{{ image("api/api_category_options.png", "Part category options") }}
|
||||
{% with id="api_cat_options", url="api/api_category_options.png", description="Part category options" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
You can see here a detailed list of the various fields which are available for this API endpoint.
|
||||
|
||||
@@ -31,7 +33,9 @@ The `OPTIONS` endpoint provides the following information:
|
||||
|
||||
Specific details are provided on the available attributes of each field:
|
||||
|
||||
{{ image("api/api_metadata_fields.png", "Metadata fields") }}
|
||||
{% with id="api_fields", url="api/api_metadata_fields.png", description="Metadata fields" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Field Types
|
||||
|
||||
@@ -78,5 +82,10 @@ Field *label* and *help text* values are localized using the [community contribu
|
||||
|
||||
For example, the same forms (in the web interface) are served via identical API requests, with the locale information determined "on the fly":
|
||||
|
||||
{{ image("api/api_english.png", "API forms (english)") }}
|
||||
{{ image("api/api_german.png", "API forms (german)") }}
|
||||
{% with id="api_english", url="api/api_english.png", description="API forms (english)" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
{% with id="api_german", url="api/api_german.png", description="API forms (german)" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -6,7 +6,7 @@ title: Python Currency Support
|
||||
|
||||
InvenTree provides native support for multiple currencies, which can mean that data require conversion between these currencies, at defined exchange rates.
|
||||
|
||||
The InvenTree server maintains a set of exchange rates, which are updated periodically. These exchange rates are available via the [InvenTree API](../index.md), and can be used by the Python bindings.
|
||||
The InvenTree server maintains a set of exchange rates, which are updated periodically. These exchange rates are available via the [InvenTree API](../api.md), and can be used by the Python bindings.
|
||||
|
||||
### CurrencyManager Class
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ print("Minimum stock:", part.minimum_stock)
|
||||
|
||||
### Adding Parameters
|
||||
|
||||
Each [part](../../part/index.md) can have multiple [parameters](../../part/parameter.md). For the example of the sofa (above) *length* and *weight* make sense. Each parameter has a parameter template that combines the parameter name with a unit. So we first have to create the parameter templates and afterwards add the parameter values to the sofa.
|
||||
Each [part](../../part/part.md) can have multiple [parameters](../../part/parameter.md). For the example of the sofa (above) *length* and *weight* make sense. Each parameter has a parameter template that combines the parameter name with a unit. So we first have to create the parameter templates and afterwards add the parameter values to the sofa.
|
||||
|
||||
```python
|
||||
from inventree.part import Parameter
|
||||
@@ -190,7 +190,7 @@ item.transferStock(loc, quantity=50)
|
||||
|
||||
### Delete a Part
|
||||
|
||||
To delete a [Part instance](../../part/index.md), first in needs to be marked as *inactive* (otherwise it will throw an error):
|
||||
To delete a [Part instance](../../part/part.md), first in needs to be marked as *inactive* (otherwise it will throw an error):
|
||||
|
||||
```python
|
||||
from inventree.part import Part
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
---
|
||||
title: Python Interface
|
||||
---
|
||||
|
||||
## Python Module
|
||||
|
||||
A [Python module](https://github.com/inventree/inventree-python) is provided for rapid development of third party scripts or applications using the REST API. The python module handles authentication and API transactions, providing an extremely clean interface for interacting with and manipulating database data.
|
||||
|
||||
### Features
|
||||
|
||||
- Automatic authentication management using token-based authentication
|
||||
- Pythonic data access
|
||||
- Native file uploads
|
||||
- Powerful functions for accessing related model data
|
||||
|
||||
### Installation
|
||||
|
||||
The inventree python interface can be easily installed via the [PIP package manager](https://pypi.org/project/inventree/):
|
||||
|
||||
```
|
||||
pip3 install inventree
|
||||
```
|
||||
|
||||
!!! tip "Upgrading"
|
||||
To upgrade to the latest version, run `pip install --upgrade inventree`
|
||||
|
||||
Alternatively, it can downloaded and installed from source, from [GitHub](https://github.com/inventree/inventree-python).
|
||||
|
||||
### Authentication
|
||||
|
||||
Authentication against an InvenTree server is simple:
|
||||
|
||||
#### Basic Auth
|
||||
|
||||
Connect using your username/password as follows:
|
||||
|
||||
```python
|
||||
from inventree.api import InvenTreeAPI
|
||||
|
||||
SERVER_ADDRESS = 'http://127.0.0.1:8000'
|
||||
MY_USERNAME = 'not_my_real_username'
|
||||
MY_PASSWORD = 'not_my_real_password'
|
||||
|
||||
api = InvenTreeAPI(SERVER_ADDRESS, username=MY_USERNAME, password=MY_PASSWORD)
|
||||
```
|
||||
|
||||
#### Token Auth
|
||||
|
||||
Alternatively, if you already have an access token:
|
||||
|
||||
```python
|
||||
api = InvenTreeAPI(SERVER_ADDRESS, token=MY_TOKEN)
|
||||
```
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
Authentication variables can also be set using environment variables:
|
||||
|
||||
- `INVENTREE_API_HOST`
|
||||
- `INVENTREE_API_USERNAME`
|
||||
- `INVENTREE_API_PASSWORD`
|
||||
- `INVENTREE_API_TOKEN`
|
||||
|
||||
And simply connect as follows:
|
||||
|
||||
```python
|
||||
api = InvenTreeAPI()
|
||||
```
|
||||
|
||||
### Retrieving Data
|
||||
|
||||
Once a connection is established to the InvenTree server, querying individual items is simple.
|
||||
|
||||
#### Single Item
|
||||
|
||||
If the primary-key of an object is already known, retrieving it from the database is performed as follows:
|
||||
|
||||
```python
|
||||
from inventree.part import PartCategory
|
||||
|
||||
category = PartCategory(api, 10)
|
||||
```
|
||||
|
||||
#### Multiple Items
|
||||
|
||||
Database items can be queried by using the `list` method for the given class. Note that arbitrary filter parameters can be applied (as specified by the [InvenTree API](../index.md)) to filter the returned results.
|
||||
|
||||
```python
|
||||
from inventree.part import Part
|
||||
from inventree.stock import StockItem
|
||||
|
||||
parts = Part.list(api, category=10, assembly=True)
|
||||
items = StockItem.list(api, location=4, part=24)
|
||||
```
|
||||
|
||||
The `items` variable above provides a list of `StockItem` objects.
|
||||
|
||||
#### Filtering by parent
|
||||
|
||||
In tree based models the child items could be filtered by using the parent keyword:
|
||||
|
||||
```python
|
||||
from inventree.part import PartCategory
|
||||
|
||||
child_categories = PartCategory.list(api, parent=10)
|
||||
```
|
||||
|
||||
The top level items can can be queried by passing empty string as a parent filter:
|
||||
|
||||
```python
|
||||
from inventree.part import PartCategory
|
||||
|
||||
parent_categories = PartCategory.list(api, parent='')
|
||||
```
|
||||
|
||||
### Item Attributes
|
||||
|
||||
The available model attributes are determined by introspecting [API metadata](../metadata.md). To view the fields (attributes) available for a given database model type within the python interface, use the `fieldNames` and `fieldInfo` methods, as below:
|
||||
|
||||
```python
|
||||
from inventree.api import InvenTreeAPI
|
||||
from inventree.part import Part
|
||||
|
||||
api = InvenTreeAPI("http://localhost:8000", username="admin", password="inventree")
|
||||
|
||||
fields = Part.fieldNames(api)
|
||||
|
||||
for field in Part.fieldNames(api):
|
||||
print(field, '->', Part.fieldInfo(field, api))
|
||||
```
|
||||
|
||||
```
|
||||
active -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Active', 'help_text': 'Is this part active?', 'default': True, 'max_length': None}
|
||||
allocated_to_build_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to build orders'}
|
||||
allocated_to_sales_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to sales orders'}
|
||||
assembly -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Assembly', 'help_text': 'Can this part be built from other parts?', 'default': False, 'max_length': None}
|
||||
category -> {'type': 'related field', 'required': True, 'read_only': False, 'label': 'Category', 'model': 'partcategory', 'api_url': '/api/part/category/', 'filters': {}, 'help_text': 'Part category', 'max_length': None}
|
||||
component -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Component', 'help_text': 'Can this part be used to build other parts?', 'default': True, 'max_length': None}
|
||||
default_expiry -> {'type': 'integer', 'required': True, 'read_only': False, 'label': 'Default Expiry', 'help_text': 'Expiry time (in days) for stock items of this part', 'min_value': 0, 'max_value': 2147483647, 'default': 0, 'max_length': None}
|
||||
...
|
||||
variant_stock -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Variant stock'}
|
||||
```
|
||||
|
||||
|
||||
### Item Methods
|
||||
|
||||
Once an object has been retrieved from the database, its related objects can be returned with the provided helper methods:
|
||||
|
||||
```python
|
||||
part = Part(api, 25)
|
||||
stock_items = part.getStockItems()
|
||||
```
|
||||
|
||||
Some classes also have helper functions for performing certain actions, such as uploading file attachments or test results:
|
||||
|
||||
```python
|
||||
stock_item = StockItem(api, 1001)
|
||||
stock_item.uploadTestResult("Firmware", True, value="0x12345678", attachment="device_firmware.bin")
|
||||
```
|
||||
|
||||
#### Discovering Methods
|
||||
|
||||
You can determine the available methods by either [reading the source code](https://github.com/inventree/inventree-python) or using the `dir()` function in an interactive terminal.
|
||||
|
||||
### Further Reading
|
||||
|
||||
The [InvenTree Python Interface](https://github.com/inventree/inventree-python) is open source, and well documented. The best way to learn is to read through the source code and try for yourself!
|
||||
167
docs/docs/api/python/python.md
Normal file
@@ -0,0 +1,167 @@
|
||||
---
|
||||
title: Python Interface
|
||||
---
|
||||
|
||||
## Python Module
|
||||
|
||||
A [Python module](https://github.com/inventree/inventree-python) is provided for rapid development of third party scripts or applications using the REST API. The python module handles authentication and API transactions, providing an extremely clean interface for interacting with and manipulating database data.
|
||||
|
||||
### Features
|
||||
|
||||
- Automatic authentication management using token-based authentication
|
||||
- Pythonic data access
|
||||
- Native file uploads
|
||||
- Powerful functions for accessing related model data
|
||||
|
||||
### Installation
|
||||
|
||||
The inventree python interface can be easily installed via the [PIP package manager](https://pypi.org/project/inventree/):
|
||||
|
||||
```
|
||||
pip3 install inventree
|
||||
```
|
||||
|
||||
!!! tip "Upgrading"
|
||||
To upgrade to the latest version, run `pip install --upgrade inventree`
|
||||
|
||||
Alternatively, it can downloaded and installed from source, from [GitHub](https://github.com/inventree/inventree-python).
|
||||
|
||||
### Authentication
|
||||
|
||||
Authentication against an InvenTree server is simple:
|
||||
|
||||
#### Basic Auth
|
||||
|
||||
Connect using your username/password as follows:
|
||||
|
||||
```python
|
||||
from inventree.api import InvenTreeAPI
|
||||
|
||||
SERVER_ADDRESS = 'http://127.0.0.1:8000'
|
||||
MY_USERNAME = 'not_my_real_username'
|
||||
MY_PASSWORD = 'not_my_real_password'
|
||||
|
||||
api = InvenTreeAPI(SERVER_ADDRESS, username=MY_USERNAME, password=MY_PASSWORD)
|
||||
```
|
||||
|
||||
#### Token Auth
|
||||
|
||||
Alternatively, if you already have an access token:
|
||||
|
||||
```python
|
||||
api = InvenTreeAPI(SERVER_ADDRESS, token=MY_TOKEN)
|
||||
```
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
Authentication variables can also be set using environment variables:
|
||||
|
||||
- `INVENTREE_API_HOST`
|
||||
- `INVENTREE_API_USERNAME`
|
||||
- `INVENTREE_API_PASSWORD`
|
||||
- `INVENTREE_API_TOKEN`
|
||||
|
||||
And simply connect as follows:
|
||||
|
||||
```python
|
||||
api = InvenTreeAPI()
|
||||
```
|
||||
|
||||
### Retrieving Data
|
||||
|
||||
Once a connection is established to the InvenTree server, querying individual items is simple.
|
||||
|
||||
#### Single Item
|
||||
|
||||
If the primary-key of an object is already known, retrieving it from the database is performed as follows:
|
||||
|
||||
```python
|
||||
from inventree.part import PartCategory
|
||||
|
||||
category = PartCategory(api, 10)
|
||||
```
|
||||
|
||||
#### Multiple Items
|
||||
|
||||
Database items can be queried by using the `list` method for the given class. Note that arbitrary filter parameters can be applied (as specified by the [InvenTree API](../api.md)) to filter the returned results.
|
||||
|
||||
```python
|
||||
from inventree.part import Part
|
||||
from inventree.stock import StockItem
|
||||
|
||||
parts = Part.list(api, category=10, assembly=True)
|
||||
items = StockItem.list(api, location=4, part=24)
|
||||
```
|
||||
|
||||
The `items` variable above provides a list of `StockItem` objects.
|
||||
|
||||
#### Filtering by parent
|
||||
|
||||
In tree based models the child items could be filtered by using the parent keyword:
|
||||
|
||||
```python
|
||||
from inventree.part import PartCategory
|
||||
|
||||
child_categories = PartCategory.list(api, parent=10)
|
||||
```
|
||||
|
||||
The top level items can can be queried by passing empty string as a parent filter:
|
||||
|
||||
```python
|
||||
from inventree.part import PartCategory
|
||||
|
||||
parent_categories = PartCategory.list(api, parent='')
|
||||
```
|
||||
|
||||
### Item Attributes
|
||||
|
||||
The available model attributes are determined by introspecting [API metadata](../metadata.md). To view the fields (attributes) available for a given database model type within the python interface, use the `fieldNames` and `fieldInfo` methods, as below:
|
||||
|
||||
```python
|
||||
from inventree.api import InvenTreeAPI
|
||||
from inventree.part import Part
|
||||
|
||||
api = InvenTreeAPI("http://localhost:8000", username="admin", password="inventree")
|
||||
|
||||
fields = Part.fieldNames(api)
|
||||
|
||||
for field in Part.fieldNames(api):
|
||||
print(field, '->', Part.fieldInfo(field, api))
|
||||
```
|
||||
|
||||
```
|
||||
active -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Active', 'help_text': 'Is this part active?', 'default': True, 'max_length': None}
|
||||
allocated_to_build_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to build orders'}
|
||||
allocated_to_sales_orders -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Allocated to sales orders'}
|
||||
assembly -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Assembly', 'help_text': 'Can this part be built from other parts?', 'default': False, 'max_length': None}
|
||||
category -> {'type': 'related field', 'required': True, 'read_only': False, 'label': 'Category', 'model': 'partcategory', 'api_url': '/api/part/category/', 'filters': {}, 'help_text': 'Part category', 'max_length': None}
|
||||
component -> {'type': 'boolean', 'required': True, 'read_only': False, 'label': 'Component', 'help_text': 'Can this part be used to build other parts?', 'default': True, 'max_length': None}
|
||||
default_expiry -> {'type': 'integer', 'required': True, 'read_only': False, 'label': 'Default Expiry', 'help_text': 'Expiry time (in days) for stock items of this part', 'min_value': 0, 'max_value': 2147483647, 'default': 0, 'max_length': None}
|
||||
...
|
||||
variant_stock -> {'type': 'float', 'required': True, 'read_only': True, 'label': 'Variant stock'}
|
||||
```
|
||||
|
||||
|
||||
### Item Methods
|
||||
|
||||
Once an object has been retrieved from the database, its related objects can be returned with the provided helper methods:
|
||||
|
||||
```python
|
||||
part = Part(api, 25)
|
||||
stock_items = part.getStockItems()
|
||||
```
|
||||
|
||||
Some classes also have helper functions for performing certain actions, such as uploading file attachments or test results:
|
||||
|
||||
```python
|
||||
stock_item = StockItem(api, 1001)
|
||||
stock_item.uploadTestResult("Firmware", True, value="0x12345678", attachment="device_firmware.bin")
|
||||
```
|
||||
|
||||
#### Discovering Methods
|
||||
|
||||
You can determine the available methods by either [reading the source code](https://github.com/inventree/inventree-python) or using the `dir()` function in an interactive terminal.
|
||||
|
||||
### Further Reading
|
||||
|
||||
The [InvenTree Python Interface](https://github.com/inventree/inventree-python) is open source, and well documented. The best way to learn is to read through the source code and try for yourself!
|
||||
@@ -7,7 +7,7 @@ The API schema as documented below is generated using the [drf-spectactular](htt
|
||||
|
||||
## API Version
|
||||
|
||||
This documentation is for API version: `352`
|
||||
This documentation is for API version: `171`
|
||||
|
||||
!!! tip "API Schema History"
|
||||
We track API schema changes, and provide a snapshot of each API schema version in the [API schema repository](https://github.com/inventree/schema/).
|
||||
|
||||
33
docs/docs/app/app.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: InvenTree Mobile App
|
||||
---
|
||||
|
||||
{% with directory="appgallery", per_page=2 %}
|
||||
{% include "carousel.html" %}
|
||||
{% endwith %}
|
||||
|
||||
-----
|
||||
|
||||
The InvenTree Mobile App brings stock control to your pocket. Integrating seamlessly with the [InvenTree API](../api/api.md), the app provides immediate access to inventory data without requiring physical access to a computer.
|
||||
|
||||
Native barcode support provides a multitude of context-sensitive stock control actions, allowing streamlined inventory management at your fingertips. The app has been optimized for speed, providing instant access to stock knowledge and handy on-site functionality.
|
||||
|
||||
## Features
|
||||
|
||||
- View and edit part and stock information with a blazingly fast interface
|
||||
- Perform stock control actions on the go
|
||||
- Barcode integrations simply stock operations
|
||||
- Receive purchase orders and check in stock items
|
||||
- And many more!
|
||||
|
||||
## Download
|
||||
|
||||
The InvenTree app can be downloaded from either the Android or Apple app stores, or accessed via the links below:
|
||||
|
||||
### Android
|
||||
|
||||
<span class='fab fa-android'></span> [Android Play Store](https://play.google.com/store/apps/details?id=inventree.inventree_app).
|
||||
|
||||
### iOS
|
||||
|
||||
<span class='fab fa-apple'></span> [Apple App Store](https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone)
|
||||
@@ -53,7 +53,9 @@ If a match is found, the app will navigate to the relevant page.
|
||||
|
||||
From the [Stock Location detail page](./stock.md#stock-location-view), multiple barcode actions may be available:
|
||||
|
||||
{{ image("app/barcode_stock_location_actions.png", "Stock location barcode actions") }}
|
||||
{% with id="location-actions", url="app/barcode_stock_location_actions.png", maxheight="240px", description="Stock location barcode actions" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
#### Assign Barcode
|
||||
|
||||
@@ -75,7 +77,9 @@ the *Scan Items Into Location* action allows you to scan items into the selected
|
||||
|
||||
From the [Stock Item detail page](./stock.md#stock-item-detail-view), the following barcode actions may be available:
|
||||
|
||||
{{ image("app/barcode_stock_item_actions.png", "Stock item barcode actions") }}
|
||||
{% with id="item-actions", url="app/barcode_stock_item_actions.png", maxheight="240px", description="Stock item barcode actions" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
#### Assign Barcode
|
||||
|
||||
@@ -89,7 +93,9 @@ Scan the selected stock item into a stock location. Scanning a valid barcode ass
|
||||
|
||||
From the [Part detail page](./part.md#part-detail-view), the following barcode actions are available:
|
||||
|
||||
{{ image("app/barcode_part_actions.png", "Part barcode actions") }}
|
||||
{% with id="part-actions", url="app/barcode_part_actions.png", maxheight="240px", description="Part barcode actions" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
#### Assign Barcode
|
||||
|
||||
@@ -99,7 +105,9 @@ Assign a custom barcode to the selected part. Scanning a barcode (which is not a
|
||||
|
||||
From the [Purchase Order detail page](./po.md#purchase-order-detail) page, the following barcode actions are available:
|
||||
|
||||
{{ image("app/barcode_po_actions.png", "Purchase order barcode actions") }}
|
||||
{% with id="po-actions", url="app/barcode_po_actions.png", maxheight="240px", description="Purchase order barcode actions" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
#### Scan Received Parts
|
||||
|
||||
|
||||
@@ -8,20 +8,27 @@ Use of the InvenTree app assumes that you (the user) have access to an InvenTree
|
||||
|
||||
When first running the app, no profile has been configured. The *server* icon in the top-right corner of the home screen is <span style='color: red'>red</span>, indicating that there is no connection to an InvenTree server:
|
||||
|
||||
{{ image("app/initial.png", "No server configured") }}
|
||||
{% with id="no_server", url="app/initial.png", maxheight="240px", description="No server configured" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
Press on the server icon to navigate to the server selection view:
|
||||
|
||||
{{ image("app/no_profiles.png", "No server configured") }}
|
||||
{% with id="no_profiles", url="app/no_profiles.png", maxheight="240px", description="No server configured" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
### Create Server
|
||||
|
||||
!!! success "Server Profiles"
|
||||
The app supports multiple server profiles, providing simple switching between different InvenTree servers and/or account profiles.
|
||||
|
||||
Press the {{ icon("circle-plus", color="blue") }} button in the bottom-right corner of the screen to create a new server profile.
|
||||
Press the <span class='fas fa-plus-circle blue'></span> button in the bottom-right corner of the screen to create a new server profile.
|
||||
|
||||
{{ image("app/add_server_profile.png", "Add server profile") }}
|
||||
{% with id="add_profile", url="app/add_server_profile.png", maxheight="240px", description="Add server" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
Enter the required server details:
|
||||
|
||||
@@ -38,18 +45,24 @@ Once the server profile is created, you need to connect to the server. Simply sh
|
||||
|
||||
Alternatively, long press on the server profile to activate the context menu, then select *Connect to Server*.
|
||||
|
||||
When the app successfully connects to the server, a success message is briefly displayed at the bottom of the screen. A green {{ icon("circle-check", color="green") }} icon next to the server profile indicate that the profile is currently *selected* and also the connection was successful.
|
||||
When the app successfully connects to the server, a success message is briefly displayed at the bottom of the screen. A green <span class='fas fa-check-circle green'></span> icon next to the server profile indicate that the profile is currently *selected* and also the connection was successful.
|
||||
|
||||
{{ image("app/connected.png", "Connected to server") }}
|
||||
{% with id="connected", url="app/connected.png", maxheight="240px", description="Connected to server" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Connection Failure
|
||||
|
||||
If (for whatever reason) the app does not successfully connect to the InvenTree server, a failure message is displayed, and a red {{ icon("circle-x", color="red") }} icon is displayed next to the server profile.
|
||||
If (for whatever reason) the app does not successfully connect to the InvenTree server, a failure message is displayed, and a red <span class='fas fa-times-circle red'></span> icon is displayed next to the server profile.
|
||||
|
||||
{{ image("app/unauthorized.png", "Connection failure") }}
|
||||
{% with id="failed", url="app/unauthorized.png", maxheight="240px", description="Connection failure" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
In this case, the error message displayed at the bottom of the screen provides context as to why the app could not successfully connect to the server.
|
||||
|
||||
To edit the server profile details, long press on the server profile, and select *Edit Server Profile*:
|
||||
|
||||
{{ image("app/edit_server.png", "Edit server profile") }}
|
||||
{% with id="edit", url="app/edit_server.png", maxheight="240px", description="Edit server profile" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
title: InvenTree Mobile App
|
||||
---
|
||||
|
||||
{% with directory="appgallery", per_page=2 %}
|
||||
{% include "carousel.html" %}
|
||||
{% endwith %}
|
||||
|
||||
-----
|
||||
|
||||
The InvenTree Mobile App brings stock control to your pocket. Integrating seamlessly with the [InvenTree API](../api/index.md), the app provides immediate access to inventory data without requiring physical access to a computer.
|
||||
|
||||
Native barcode support provides a multitude of context-sensitive stock control actions, allowing streamlined inventory management at your fingertips. The app has been optimized for speed, providing instant access to stock knowledge and handy on-site functionality.
|
||||
|
||||
## Features
|
||||
|
||||
- View and edit part and stock information with a blazingly fast interface
|
||||
- Perform stock control actions on the go
|
||||
- Barcode integrations simply stock operations
|
||||
- Receive purchase orders and check in stock items
|
||||
- And many more!
|
||||
|
||||
## Download
|
||||
|
||||
The InvenTree app can be downloaded from either the Android or Apple app stores, or accessed via the links below:
|
||||
|
||||
### Android
|
||||
|
||||
<span class='fab fa-android'></span> [Android Play Store](https://play.google.com/store/apps/details?id=inventree.inventree_app).
|
||||
|
||||
### iOS
|
||||
|
||||
<span class='fab fa-apple'></span> [Apple App Store](https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone)
|
||||
@@ -7,13 +7,17 @@ title: App Navigation
|
||||
|
||||
The app *home screen* provides quick-access buttons for stock view and actions:
|
||||
|
||||
{{ image("app/home.png", "Home screen") }}
|
||||
{% with id="home", url="app/home.png", maxheight="240px", description="Home screen" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
## Tab Display
|
||||
|
||||
Some screens provide multiple tabbed views, which are displayed at the top of the screen:
|
||||
|
||||
{{ image("app/app_tabs.png", "App tabs") }}
|
||||
{% with id="global_nav", url="app/app_tabs.png", maxheight="240px", description="App tabs" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
Tabs can be navigated by pressing on the text of each tab, or by scrolling the screen left or right.
|
||||
|
||||
@@ -21,13 +25,17 @@ Tabs can be navigated by pressing on the text of each tab, or by scrolling the s
|
||||
|
||||
The *Global Action* buttons are visible on most screens, displayed in the bottom left corner of the screen:
|
||||
|
||||
{{ image("app/app_global_navigation.png", "Global navigation actions") }}
|
||||
{% with id="global_nav", url="app/app_global_navigation.png", maxheight="240px", description="Global navigation actions" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Open Drawer Menu
|
||||
|
||||
The {{ icon("list") }} action opens the *Drawer Menu*, which is a quick-access menu for global navigation:
|
||||
The <span class='fas fa-list'></span> action opens the *Drawer Menu*, which is a quick-access menu for global navigation:
|
||||
|
||||
{{ image("app/drawer.png", "Open drawer menu") }}
|
||||
{% with id="drawer", url="app/drawer.png", maxheight="240px", description="Open drawer menu" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
The *Drawer Menu* can be accessed in the following ways:
|
||||
|
||||
@@ -36,17 +44,19 @@ The *Drawer Menu* can be accessed in the following ways:
|
||||
|
||||
### Search
|
||||
|
||||
The {{ icon("search", title="Search") }} action opens the [Search](./search.md) screen
|
||||
The <span class='fas fa-search'></span> action opens the [Search](./search.md) screen
|
||||
|
||||
### Scan Barcode
|
||||
|
||||
The {{ icon("barcode", title="Scan") }} action opens the [barcode scan](./barcode.md#global-scan) window, which allows quick access to the barcode scanning functionality.
|
||||
The <span class='fas fa-qrcode'></span> action opens the [barcode scan](./barcode.md#global-scan) window, which allows quick access to the barcode scanning functionality.
|
||||
|
||||
## Context Actions
|
||||
|
||||
Within a given view, certain context actions may be available. If there are contextual actions which can be performed, they are displayed in the bottom right corner:
|
||||
|
||||
{{ image("app/context_actions.png", "Context actions") }}
|
||||
{% with id="drawer", url="app/context_actions.png", maxheight="240px", description="Context actions" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
!!! tip "Barcode Actions"
|
||||
Available barcode actions are displayed in a separate context action menu
|
||||
|
||||
@@ -10,7 +10,9 @@ From the *home screen*, select *Parts* to open the top-level part category view.
|
||||
|
||||
The *Details* tab shows information about the selected part category. In particular, it shows the name and description of the category, a link to the parent category (if available) and a list of subcategories.
|
||||
|
||||
{{ image("app/part_category_detail.png", "Part Category") }}
|
||||
{% with id="part-category", url="part_category_detail.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Parent Category
|
||||
|
||||
@@ -24,35 +26,47 @@ If the current category has any subcategories, these are listed here. Select any
|
||||
|
||||
The *Parts* tab displays all the parts available in this category. Tap a displayed part to navigate to the part detail view.
|
||||
|
||||
{{ image("app/category_parts_tab.png", "Category Parts") }}
|
||||
{% with id="cat-parts", url="category_parts_tab.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
The list of available parts can be filtered using the input box at the top of the screen:
|
||||
|
||||
{{ image("app/category_parts_filter.png", "Category Parts Filter") }}
|
||||
{% with id="cat-parts-filter", url="category_parts_filter.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Context Actions
|
||||
|
||||
The following *Context Actions* are available for the selected category:
|
||||
|
||||
{{ image("app/category_actions_tab.png", "Category Actions") }}
|
||||
{% with id="cat-actions", url="category_actions_tab.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### New Category
|
||||
|
||||
Create a new subcategory under the current category:
|
||||
|
||||
{{ image("app/new_category.jpg", "New Category") }}
|
||||
{% with id="cat-new-cat", url="new_category.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### New Part
|
||||
|
||||
Create a new part within the current category:
|
||||
|
||||
{{ image("app/new_part.jpg", "New Part") }}
|
||||
{% with id="cat-new-part", url="new_part.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Edit Category
|
||||
|
||||
Select the *Edit* button in the top right corner of the screen to edit the details for the selected part category:
|
||||
|
||||
{{ image("app/part_category_edit.jpg", "Edit Category") }}
|
||||
{% with id="cat-edit", url="part_category_edit.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
!!! info "Permission Required"
|
||||
If the user does not have permission to edit part details, this button will be hidden
|
||||
@@ -63,7 +77,9 @@ In the part category display screen, there are three tabs of information availab
|
||||
|
||||
The *Part Detail* view displays information about a single part:
|
||||
|
||||
{{ image("app/part_details.png", "Part Detail") }}
|
||||
{% with id="part-details", url="part_details.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Details Tab
|
||||
|
||||
@@ -81,13 +97,17 @@ The *stock* tile shows the total quantity of stock available for the part. Tap o
|
||||
|
||||
Tap on the *notes* tile to view (and edit) the notes for this part:
|
||||
|
||||
{{ image("app/part_notes.jpg", "Part Notes") }}
|
||||
{% with id="part-notes", url="part_notes.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Attachments
|
||||
|
||||
Tap on the *attachments* tile to view the file attachments for this part:
|
||||
|
||||
{{ image("app/part_attachments.jpg", "Part Attachments") }}
|
||||
{% with id="part-attachments", url="part_attachments.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
New attachments can be uploaded by tapping on the icons in the top right of the screen.
|
||||
|
||||
@@ -97,7 +117,9 @@ Select a particular attachment file to downloaded it to the local device.
|
||||
|
||||
The *Stock* tab displays all the stock items available for this part. Tap on a particular stock item to navigate to a detail view for that item.
|
||||
|
||||
{{ image("app/part_stock.png", "Part Stock") }}
|
||||
{% with id="part-stock", url="part_stock.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
The list of available stock items can be filtered using the input box at the top of the screen.
|
||||
|
||||
@@ -109,13 +131,17 @@ The *Actions* tab displays the available actions for the selected part:
|
||||
|
||||
Create a new stock item for this part:
|
||||
|
||||
{{ image("app/new_stock_item.jpg", "New Stock Item") }}
|
||||
{% with id="part-stock-new", url="new_stock_item.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Edit Part
|
||||
|
||||
To edit the part details, select the *Edit* button in the top right corner of the screen:
|
||||
|
||||
{{ image("app/part_edit.jpg", "Edit Part") }}
|
||||
{% with id="part-edit", url="part_edit.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
!!! info "Permission Required"
|
||||
If the user does not have permission to edit part details, this button will be hidden
|
||||
@@ -124,6 +150,8 @@ To edit the part details, select the *Edit* button in the top right corner of th
|
||||
|
||||
Tap the image of the part (displayed at the top left of the screen) to launch the part image view:
|
||||
|
||||
{{ image("app/part_image.jpg", "Part Image") }}
|
||||
{% with id="part-image", url="part_image.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
A full-screen view of the image is displayed. The user can also upload a new image for the part, either selecting an image from the device, or taking a new picture with the device's camera.
|
||||
|
||||
@@ -6,7 +6,9 @@ title: Purchase Orders
|
||||
|
||||
The purchase order list display lists all purchase orders:
|
||||
|
||||
{{ image("app/po_list.png", "Purchase order list") }}
|
||||
{% with id="po_list", url="app/po_list.png", maxheight="240px", description="Purchase order list" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
Select an individual purchase order to display the detail view for that order.
|
||||
|
||||
@@ -16,19 +18,25 @@ Displayed purchase orders can be subsequently filtered using the search input at
|
||||
|
||||
## Purchase Order Detail
|
||||
|
||||
{{ image("app/po_detail.png", "Purchase order detail") }}
|
||||
{% with id="po_detail", url="app/po_detail.png", maxheight="240px", description="Purchase order details" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Edit Order Details
|
||||
|
||||
From the detail view, select the *Edit* button in the top-right of the screen. This opens the purchase order editing display:
|
||||
|
||||
{{ image("app/po_edit.png", "Edit purchase order") }}
|
||||
{% with id="edit_po", url="app/po_edit.png", maxheight="240px", description="Edit purchase order" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Line Items
|
||||
|
||||
The *Line Items* tab shows the line items associated with this purchase order:
|
||||
|
||||
{{ image("app/po_lines.png", "Purchase order line items") }}
|
||||
{% with id="po_lines", url="app/po_lines.png", maxheight="240px", description="Purchase order line items" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
Long press on a particular line item to receive the item into stock.
|
||||
|
||||
@@ -36,4 +44,6 @@ Long press on a particular line item to receive the item into stock.
|
||||
|
||||
Once items have been received into stock against a particular purchase order, they are displayed in the *Stock Items* tab:
|
||||
|
||||
{{ image("app/po_stock.png", "Purchase order stock items") }}
|
||||
{% with id="po_stock", url="app/po_stock.png", maxheight="240px", description="Purchase order stock items" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -6,5 +6,10 @@ title: App Search
|
||||
|
||||
The global search screen provides quick search functionality across the connected InvenTree database. Entering a search term will return multiple search results, as shown in the examples below:
|
||||
|
||||
{{ image("app/search_1.png", "Search results") }}
|
||||
{{ image("app/search_2.png", "Search results") }}
|
||||
{% with id="search_1", url="app/search_1.png", maxheight="240px", description="Search results" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
{% with id="search_2", url="app/search_2.png", maxheight="240px", description="Search results" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -17,13 +17,18 @@ The main settings view is shown below, and provides the following options:
|
||||
| [Part](#part-settings) | Configure part management options |
|
||||
| About | Display app version information |
|
||||
|
||||
{{ image("app/settings.png", "Settings view") }}
|
||||
|
||||
{% with id="settings_view", url="app/settings.png", maxheight="240px", description="Settings view" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
## App Settings
|
||||
|
||||
The *App Settings* view provides configuration options for the InvenTree app:
|
||||
|
||||
{{ image("app/app_settings.png", "App settings") }}
|
||||
{% with id="app_settings", url="app/app_settings.png", maxheight="240px", description="App Settings" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### App Settings
|
||||
|
||||
@@ -52,7 +57,9 @@ Configure audible app notifications:
|
||||
|
||||
The *Barcode Settings* view allows you to configure options relating to [barcode scanning](./barcode.md):
|
||||
|
||||
{{ image("app/barcode_settings.png", "Barcode settings") }}
|
||||
{% with id="barcode_settings", url="app/barcode_settings.png", maxheight="240px", description="Barcode Settings" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
| Option | Description |
|
||||
| --- | --- |
|
||||
@@ -63,7 +70,9 @@ The *Barcode Settings* view allows you to configure options relating to [barcode
|
||||
|
||||
The *Home Screen* view allows you to configure display options for the app 'home screen':
|
||||
|
||||
{{ image("app/home_settings.png", "Home screen settings") }}
|
||||
{% with id="home_settings", url="app/home_settings.png", maxheight="240px", description="Home Screen Settings" %}
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
| Option | Description |
|
||||
| --- | --- |
|
||||
|
||||
@@ -6,7 +6,9 @@ title: Sales Orders
|
||||
|
||||
The sales order list display shows all sales orders:
|
||||
|
||||
{{ image("app/so_list.png", "Sales order list") }}
|
||||
{% with id="so_list", url="app/so_list.png", maxheight="240px", description="Sales order list" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
Select an individual sales order to display the detail view for that order.
|
||||
|
||||
@@ -18,7 +20,9 @@ Displayed sales orders can be subsequently filtered using the search input at th
|
||||
|
||||
Select an individual order to show the detailed view for that order:
|
||||
|
||||
{{ image("app/so_detail.png", "Sales order detail") }}
|
||||
{% with id="so_detail", url="app/so_detail.png", maxheight="240px", description="Sales order details" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
### Edit Order Details
|
||||
|
||||
@@ -28,4 +32,6 @@ From the detail view, select the *Edit* button in the top-right of the screen. T
|
||||
|
||||
View the line items associated with the selected order:
|
||||
|
||||
{{ image("app/so_lines.png", "Sales order line items") }}
|
||||
{% with id="so_lines", url="app/so_lines.png", maxheight="240px", description="Sales order lines" %}
|
||||
{% include "img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -10,7 +10,9 @@ From the *home screen*, select *Stock* to open the top-level stock location view
|
||||
|
||||
The *Details* tab shows information about the selected stock location.
|
||||
|
||||
{{ image("app/location_detail.png", "Stock Location") }}
|
||||
{% with id="loc-detail", url="location_detail.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Parent Location
|
||||
|
||||
@@ -24,29 +26,44 @@ If the current stock location has any sublocations, they are listed here. Select
|
||||
|
||||
The *Stock* tab displays all the stock items available in this location. Tap a displayed stock item to navigate to the stock item detail view.
|
||||
|
||||
{{ image("app/location_stock.png", "Location Stock") }}
|
||||
{% with id="loc-stock", url="location_stock.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
The list of available stock items can be filtered using the input box at the top of the screen:
|
||||
|
||||
{{ image("app/location_stock_filter.jpg", "Location Stock Filter") }}
|
||||
{% with id="loc-filter", url="location_stock_filter.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
### Context Actions
|
||||
|
||||
The following *Context Actions* are available for the selected location:
|
||||
|
||||
{{ image("app/location_actions.png", "Location Actions") }}
|
||||
{% with id="loc-actions", url="location_actions.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
#### New Location
|
||||
|
||||
Create a new location under the current location:
|
||||
|
||||
{{ image("app/new_location.jpg", "New Location") }}
|
||||
{% with id="loc-new", url="new_location.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
#### New Stock Item
|
||||
|
||||
Create a new stock item in the current location:
|
||||
|
||||
{{ image("app/new_stock_item_from_location.jpg", "New Stock Item") }}
|
||||
{% with id="loc-new-stock", url="new_stock_item_from_location.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
#### Scan Stock Items Into Location
|
||||
|
||||
@@ -57,7 +74,10 @@ Use the barcode scanner to scan a stock item into the current location.
|
||||
|
||||
The *Stock Item Detail* view displays information about a single stock item:
|
||||
|
||||
{{ image("app/stock_detail.png", "Stock Item") }}
|
||||
{% with id="stock-detail", url="stock_detail.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
||||
### Details Tab
|
||||
|
||||
@@ -79,34 +99,44 @@ Tap on the notes tile to display and edit the notes for this stock item
|
||||
|
||||
The *actions* tab displays the available actions for the selected stock item:
|
||||
|
||||
{{ image("app/stock_actions.png", "Stock Actions") }}
|
||||
{% with id="stock-actions", url="stock_actions.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Count Stock
|
||||
|
||||
Select the *Count Stock* action to validate the current number of items in stock. Use this option to perform a quick stocktake!
|
||||
|
||||
{{ image("app/stock_count.png", "Count Stock") }}
|
||||
{% with id="stock-count", url="stock_count.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
!!! info "Serialized Stock"
|
||||
The *count stock* action is not available for serialized stock items, as they have a fixed quantity of 1
|
||||
|
||||
#### Remove Stock
|
||||
|
||||
Select this action to remove a certain quantity from the selected stock item. For example, if there are 12 items available, and you take 3 items, the listed quantity will be reduced to 9 items.
|
||||
Select this action to remove a certain quantity from the selected stock item. For example, if there are 12 items available, and you take 3 items, the listed quantity will be reduced to 9 itemes.
|
||||
|
||||
{{ image("app/stock_remove.png", "Remove Stock") }}
|
||||
{% with id="stock-remove", url="stock_remove.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Add Stock
|
||||
|
||||
Select this action to add a certain quantity to the selected stock item. For example, if there are 12 items available, and you add 3 items, the listed quantity will be increased to 15 items.
|
||||
|
||||
{{ image("app/stock_add.png", "Add Stock") }}
|
||||
{% with id="stock-add", url="stock_add.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Transfer Stock
|
||||
|
||||
Transfer (move) the stock item to a new location:
|
||||
|
||||
{{ image("app/stock_transfer.png", "Transfer Stock") }}
|
||||
{% with id="stock-transfer", url="stock_transfer.png" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
#### Scan Into Location
|
||||
|
||||
@@ -122,13 +152,20 @@ This barcode can then be used to track the stock item.
|
||||
|
||||
#### Print Label
|
||||
|
||||
If the server supports [label printing plugins](../plugins/mixins/label.md), then an option to print a label for the selected stock item:
|
||||
If the server supports [label printing plugins](../extend/plugins/label.md), then an option to print a label for the selected stock item:
|
||||
|
||||
{{ image("app/stock_print_label_1.png", "Print Label") }}
|
||||
{{ image("app/stock_print_label_2.png", "Print Label") }}
|
||||
{% with id="label_print_1", url="stock_print_label_1.png", description="Print label via plugin" %}
|
||||
{% include 'app_img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
{% with id="label_print_2", url="stock_print_label_2.png", description="Print label via plugin" %}
|
||||
{% include 'app_img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
### Edit Stock Item
|
||||
|
||||
To edit the stock item details, select the *Edit* button in the top right corner of the screen:
|
||||
|
||||
{{ image("app/stock_edit.jpg", "Edit Stock Item") }}
|
||||
{% with id="stock-edit", url="stock_edit.jpg" %}
|
||||
{% include "app_img.html" %}
|
||||
{% endwith %}
|
||||
|
||||
|
Before Width: | Height: | Size: 408 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 35 KiB |
BIN
docs/docs/assets/images/admin/import.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/docs/assets/images/admin/import_error.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
docs/docs/assets/images/admin/import_preview.png
Normal file
|
After Width: | Height: | Size: 84 KiB |