Files
Odoo-Build/task
T

2306 lines
85 KiB
Bash
Executable File

#!/bin/bash
cd "$(dirname "$0")" || exit
# Commands such as git pull return exit code if there are no changes
# set -e
if [[ -a ".env" ]]; then
source .env
fi
function help-table() {
# Define column widths
cmd_width=25
opt_width=20
desc_width=90
# Print table header
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "Command" "Option" "Description"
echo "|$(printf '%*s' $((cmd_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((opt_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((desc_width + 2)) '' | tr ' ' '-')|"
# Print table rows
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "activate-venv" "" "Activate virtualenv."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "build" "[platform]" "Build Odoo Conainer image. Optionally define the target platform."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "change-uuid" "[env]" "Change database uuid via xmlrpc."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "checkout" "[branch]" "Checkout Odoo version / branch."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "checkout-config-files" "[branch]" "Checkout config files from another branch."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "checkout-revision" "[revision]" "Run Odoo revision script or checkout revision set by env var."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "clear-assets" "[db]" "Clear all assets of Odoo database."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "clear-views" "[db]" "Clear all views of Odoo database."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "clear-filestore" "[db]" "Clear local filestore folder. No param will clear all filestores. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "convert-database" "[db]" "Convert database backup file from PostgreSQL 9.5 to latest. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-module" "[path]" "Create new Odoo module from template."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-module-repo" "[path]" "Initialize Odoo module repo from template."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-revision" "[revision]" "Create new Odoo revision."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-nextcloud-env" "[env]" "Create env file for Nextcloud instance."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-odoo-env" "[env]" "Create env file for Odoo Instance."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-snippet" "[id]" "Create snippet from template."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "disable-mailserver" "[env]" "Disable mail server settings via xmlrpc."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "disable-snippet" "[env][path]" "Disable snippet definition."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "container-login" "" "Setup container hub login credentials."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "drop-db" "[db]" "Drop target Odoo database. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "edit-env" "[env]" "Open env file in default editor."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-admin-passwd" "[pass]" "Generate hash for Odoo master password."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "translate-module" "[env][path][lang]" "Generate translation for Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-help-doc" "" "Write help table to task.md file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-overview" "" "Update module overview doc file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-security" "[path][model]" "Generate model access file for a selected model of a module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-model" "[path][model]" "Generate model files from templates."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-snippet" "[path][ref]" "Generate view snippet from template."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-snippets-doc" "" "Update snippets doc file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-revisions-doc" "" "Update revisions doc file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "get-addons-path" "" "Output addons path."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "get-module-version" "[path]" "Get module version from manifest."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "get-modules" "[path][option]" "Get list of modules in path. Option is 'basename' or 'dirname'."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-feature-branch" "[path]" "Create feature branch for Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-fetch" "" "Fetch all Odoo version branches."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-mig-branch" "[path]" "Create migration branch for Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-add" "[url] [path]" "Add git submodule."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-checkout" "" "Checkout submodule commits."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-ls" "" "List submodule path space separated."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-list" "" "List path and url of submodules."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-init" "" "Init submodules listed in the .gitmodules file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-pull" "" "Pull all submodules listed in the .gitmodules file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-remove" "[path]" "Remove a git submodule."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-delete" "" "Delete all submodule folders."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-switch" "[branch]" "Switch branch for all submodules listed in the .gitmodules file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-sync" "" "Switch, stash and pull all submodules."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "import-csv" "[db][path]" "Import data from csv. Filename must match PostgreSQL table name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "info" "" "Show values of project env vars."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "init-db" "[db]" "Initialize the Odoo database. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "init-venv" "" "Initialize python virtual env."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "init-module" "[db][path,module]" "Initialize Odoo module. Default database is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "load-language" "[db][lang]" "Install language package in Odoo db."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-native" "" "Install Odoo requirements in source folder."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-odoo-scripts" "" "Install Odoo scripts."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-requirements" "[db][path]" "Install python packages from requirements.txt."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-snippet" "[env][path]" "Install snippet definition."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "k8s-apply" "" "Apply the Odoo K8s manifests."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "lint-module" "[path]" "Run pylint odoo for module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "lint-module-repo" "[path]" "Run pylint odoo for modules in repo folder."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "lint-snippets" "" "Run checks for all snippets."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "list-modules" "[path]" "Get modules in path as list."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "list-env" "" "List env files."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "list-revision" "" "List available Odoo revisions."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "llm-update" "[path]" "Feed module files with prompt to LLM and apply updates with git path."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "logs" "" "Tail Odoo container logs."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-install" "" "Install build dependencies."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-dev" "" "Start vuepress development server."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-build" "" "Create vuepress build."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-serve-build" "" "Serve vuepress build."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "odoo-cloc" "[db]" "Count custom line of codes. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "pass-store-dotenv" "" "Store content of .env in pass entry."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "pass-restore-dotenv" "" "Restore content of .env from pass entry."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "patch-database" "[db][path]" "Apply sql file to database. Default database is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "publish" "" "Publish Odoo container image."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "ps" "" "List container processes."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "pytest-module" "[db][name,path]" "Run module tests with pytest."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "release-module" "[path]" "Create GitHub release for a module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove" "[name]" "Remove containers and volumes. Options: none, db, admin, odoo, mail."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove-env" "[env]" "Remove environment config."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove-module" "[db][name]" "Remove target Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove-snippet" "[env][path]" "Remove snippet definition."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "reset-views" "[db][key]" "Execute hard reset on views matching keys."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "restart" "[name]" "Restart container."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "save-config" "[name]" "Save Odoo database config."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "setup-mail" "[db]" "Setup mail config in Odoo db."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "setup-mail-sql" "[db]" "Setup mail config in Odoo db with SQL."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "set-admin" "[db]" "Sets the password for the first user in database. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "set-addons-path" "" "Set Odoo addons path env variable."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "source" "" "Source the Python virtual env."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "show-env" "[env]" "Output content of the env file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "show-revision" "[revision]" "Show references of Odoo revision."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start" "[name][db]" "Start container. Options: none, db, admin, odoo, native, mail."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-kind" "" "Start kind Kubernetes cluster."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-minikube" "" "Start minikube Kubernetes cluster."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-psql" "[db]" "Start PSQL shell in container container. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-shell" "[db]" "Start Odoo shell from source folder. Default is branch name."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "stop" "[name]" "Stop containers."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "template-odoo-rc" "" "Template the Odoo config file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "template-docker-compose" "" "Template the Docker compose file."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-container" "" "Test container environment."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-xmlrpc" "[env]" "Test json rpc connection."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-k8s" "" "Test Kubernetes environment."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-module" "[db][name,path]" "Test target Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-module-repo" "[db][path]" "Test target Odoo modules in repo folder."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-app-list" "[db]" "Update app list."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-docs" "" "Update project docs."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "upgrade-module" "[path][version]" "Upgrade code of module from target Odoo version."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "upgrade-odoo" "[db][version][mode]" "Run the Odoo upgrade scripts. Default mode ist 'test'."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-module" "[db][name,path]" "Update target Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-readme" "[path]" "Update Readme file of Odoo module collection."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-snippet" "[env][path]" "Update snippet definition."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "upload-module" "[env][path]" "Zip and upload Odoo module."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "visualize-dependencies" "[path]" "Generate visualizations of module dependencies."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "version" "" "Show version of required tools."
printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "zip-module" "[path]" "Create zip file for module."
}
function help() {
echo
echo "$1 <command> [options]"
echo
echo "commands:"
echo
help-table
echo
}
# Static env vars
PASS_ENTRY=env/Odoo-Build
ODOO_RC="odoo.conf"
ODOO_BUILD_CONFIG_DIR="$HOME/.config/odoo-build"
# Dynamic env vars
GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
ODOO_DATABASE=${ODOO_DATABASE:="$GIT_BRANCH"}
ODOO_REVISION=${ODOO_REVISION:="$GIT_BRANCH"}
ODOO_LANGUAGE=${ODOO_LANGUAGE:="de_CH"}
ODOO_PORT=${ODOO_PORT:="8069"}
POSTGRES_PORT=${POSTGRES_PORT:="5432"}
LOG_LEVEL=${LOG_LEVEL:="info"}
CONTAINER_REGISTRY=${CONTAINER_REGISTRY:="mintsystem/"}
CONTAINER_TAG=${CONTAINER_TAG:="odoo:${ODOO_REVISION}"}
CONTAINER_CONFIG="$HOME/.docker/$CONTAINER_REGISTRY"
BROWSER_OPEN=${BROWSER_OPEN:=true}
ODOO_REVISION_CONTAINER_PULL=${ODOO_REVISION_CONTAINER_PULL:=true}
CONTAINER_ENGINE=${CONTAINER_ENGINE:="docker"}
COMPOSE_COMMAND=${COMPOSE_COMMAND:="docker compose"}
LLM_MODEL=${LLM_MODEL:="deepseek-coder"}
# Conditional env vars
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
COMPOSE_COMMAND="podman-compose"
fi
if [ -n "$SERVER_WIDE_MODULES" ]; then
SERVER_WIDE_MODULES="base,web,$SERVER_WIDE_MODULES"
else
SERVER_WIDE_MODULES="base,web"
fi
if [[ "$(uname)" == "Darwin" ]]; then
OS_RELEASE="Darwin"
PYTHON_NOTIFY=""
OS_OPEN="open"
else
OS_RELEASE=$(awk -F= '/^NAME/{print $2}' /etc/os-release | tr -d '"')
PYTHON_NOTIFY="inotify"
OS_OPEN="xdg-open"
fi
# Help Commands
function info() {
set-addons-path
echo "OS Release: $OS_RELEASE"
echo "Git Branch: $GIT_BRANCH"
echo "Odoo Revision: $ODOO_REVISION"
echo "Odoo Port: $ODOO_PORT"
echo "Postgres Port: $POSTGRES_PORT"
echo "Odoo Language: $ODOO_LANGUAGE"
echo "Container Registry: $CONTAINER_REGISTRY"
echo "Container Config: $CONTAINER_CONFIG"
echo "Container Tag: $CONTAINER_TAG"
echo "Addons Path: $ADDONS_PATH"
}
function version() {
activate-venv
uv --version
wkhtmltopdf -V
if [ "$CONTAINER_ENGINE" == "docker" ]; then
docker -v
docker compose version
else
podman --version
podman-compose --version
fi
minikube version
kind version
}
function generate-admin-passwd() {
activate-venv
if test -z "$1"; then echo "\$1 is empty."; exit; fi
ODOO_PASSWORD="$1"
scripts/hash_password
}
# Environment Commands
function init-venv() {
if [ ! -d "venv$GIT_BRANCH" ]; then
echo "Init venv$GIT_BRANCH with $(uv --version)."
uv venv "venv$GIT_BRANCH"
fi
}
function activate-venv() {
echo "Source virtualenv venv$GIT_BRANCH."
source "venv$GIT_BRANCH/bin/activate"
echo "$(python --version) is active."
}
function load-env() {
ENV_FILE="$ODOO_BUILD_CONFIG_DIR/.env.$1"
echo "Load env file $ENV_FILE"
export $(cat "$ENV_FILE" | sed 's/#.*//g' | xargs)
}
function get-addons-path() {
set-addons-path
echo "$ADDONS_PATH"
}
function template-odoo-rc() {
echo "Template $ODOO_RC"
export SERVER_WIDE_MODULES
export MODULE_AUTO_INSTALL_DISABLED
if [ -n "$GIT_SSH_PRIVATE_KEY" ]; then
GIT_SSH_PRIVATE_KEY=$(echo -e "$GIT_SSH_PRIVATE_KEY" | base64 -w0)
fi
export GIT_SSH_PRIVATE_KEY
export GIT_SSH_PUBLIC_KEY
export MAIL_DEFAULT_FROM=${MAIL_DEFAULT_FROM:="notification"}
export MAIL_CATCHALL_ALIAS=${MAIL_CATCHALL_ALIAS:="catchall"}
envsubst < "odoo.conf.template" > "$ODOO_RC"
}
function set-addons-path() {
# Read addons path from git submodules
SUBMODULES_PATH="$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }' | tr '\n' ',' | sed 's/,*$//g')"
# Remove excluded addons
EXCLUDES="addons/theme_mint_system addons/company addons/web"
for EXCLUDE in $EXCLUDES; do
SUBMODULES_PATH=$(echo "$SUBMODULES_PATH" | sed "s|${EXCLUDE},||g")
done
# Check if addons dir exist
for ADDON in $SUBMODULES_PATH; do
if [ -d "$ADDON" ]; then
echo "Path does not exist: $ADDON"
exit 1
fi
done
# Convert to native paths
ADDONS_PATH="$(echo $SUBMODULES_PATH | sed 's|odoo,|odoo/addons,|g')"
# Append paths from config env var
if [ -n "$ODOO_ADDONS_PATH" ]; then
ADDONS_PATH="${ODOO_ADDONS_PATH},${ADDONS_PATH}"
fi
}
function init-config-dir() {
echo "Ensure $ODOO_BUILD_CONFIG_DIR exists"
mkdir -p "$ODOO_BUILD_CONFIG_DIR"
}
function create-odoo-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
init-config-dir
ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
if [ -f "$ENV_FILEPATH" ]; then
echo "Env file already exists: $ENV_FILEPATH"
exit 1
fi
echo "Init env file: $ENV_FILEPATH"
echo "ODOO_URL=$ODOO_URL" > "$ENV_FILEPATH"
echo "ODOO_DATABASE=$ODOO_DATABASE" >> "$ENV_FILEPATH"
echo "ODOO_USERNAME=$ODOO_USERNAME" >> "$ENV_FILEPATH"
echo "ODOO_PASSWORD=$ODOO_PASSWORD" >> "$ENV_FILEPATH"
echo "Edit with: task edit-env $1"
}
function create-nextcloud-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
init-config-dir
ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
if [ -f "$ENV_FILEPATH" ]; then
echo "Env file already exists: $ENV_FILEPATH"
exit 1
fi
echo "Init env file: $ENV_FILEPATH"
echo "NEXTCLOUD_URL=" > "$ENV_FILEPATH"
echo "NEXTCLOUD_USERNAME=" >> "$ENV_FILEPATH"
echo "NEXTCLOUD_PASSWORD=" >> "$ENV_FILEPATH"
echo "Edit with: task edit-env $1"
}
function list-env() {
ls -a1 "$ODOO_BUILD_CONFIG_DIR"
}
function show-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
cat "$ENV_FILEPATH"
}
function edit-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
"$EDITOR" "$ENV_FILEPATH"
}
function remove-env() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
rm "$ENV_FILEPATH"
}
# Docs Commands
generate-help-doc() {
help-table > task.md
}
function update-readme() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
README_PATH="$1"
FILE_NAME=$(basename "$README_PATH")
if [[ "$FILE_NAME" != "README.md" ]]; then
README_PATH="$1/README.md"
FILE_NAME="README.md"
fi
REPO_PATH=$(dirname "$README_PATH")
MANIFEST_FILES="$REPO_PATH/*/__manifest__.py"
# Find marker in readme and clear content after
echo "Clear modules table for $README_PATH."
MARKER="## Available modules"
sed -i "/$MARKER/Q" "$README_PATH"
echo "$MARKER" >> "$README_PATH"
echo "" >> "$README_PATH"
echo "| Module | Summary |" >> "$README_PATH"
echo "| --- | --- |" >> "$README_PATH"
# Clear table after a marker
for MANIFEST_FILE in $MANIFEST_FILES; do
MODULE_DIR=$(dirname "$MANIFEST_FILE")
MODULE_NAME=$(basename "$MODULE_DIR")
echo "Add summary of $MODULE_NAME to readme file."
SUMMARY=$(grep 'summary' "$MANIFEST_FILE" -A 1 | tail -1)
echo "| [$MODULE_NAME]($MODULE_NAME) | $SUMMARY |" >> "$README_PATH"
done
}
function generate-snippets-doc() {
echo "Update snippets doc file."
echo "# Snippets" > snippets.md
echo "In Odoo everything is described as an XML document. \
Snippets are modifications (edits) for these XML documents. \
With a snippet you can e.g. hide a field on the contact form. \
A snippet name is unique and follows the \`\$COMPANY.\$MODULE.\$XML_ID.\$DESCRIPTION\` schema." >> snippets.md
PATH_URL="https://github.com/Mint-System/Odoo-Build/tree/16.0"
# Get all modules
MODULES=$(ls snippets/*.xml | xargs -n 1 basename | cut -d. -f1 | sort | uniq)
for MODULE in $MODULES; do
TITLE="${MODULE^}" # Uppercase first letter
TITLE=$(echo "$TITLE" | sed 's/_/ /g') # Replace underline with space
TITLE=$(echo "$TITLE" | sed -r 's/\<./\U&/g') # Uppercase first letter after space
# Create doc file for each module
DOCFILE="snippets/$MODULE.md"
echo -e "# $TITLE" > "$DOCFILE"
echo "## [$TITLE](snippets/$MODULE.md)" >> snippets.md
SIDEBAR_ENTRIES+="'/snippets/$MODULE.md',\n"
# Get all xml ids
XML_IDS=$(ls snippets/$MODULE.*.xml | xargs -n 1 basename | cut -d. -f2 | uniq)
for XML_ID in $XML_IDS; do
XML_ID_TITLE=$(echo "$XML_ID" | sed 's/_/ /g') # Replace underline with space
XML_ID_TITLE=$(echo "$XML_ID_TITLE" | sed -r 's/\<./\U&/g') # Uppercase first letter after space
echo "## $XML_ID_TITLE " >> "$DOCFILE"
# Process each file
FILES="snippets/$MODULE.$XML_ID.*.xml"
for FILE in $FILES; do
# Get snippet params
FILENAME=$(basename "$FILE")
EDIT=$(echo "$FILENAME" | cut -d. -f3)
EDIT_TITLE=$(echo "$EDIT" | sed 's/_/ /g') # Replace underline with space
EDIT_TITLE=$(echo "$EDIT_TITLE" | sed -r 's/\<./\U&/g') # Uppercase first letter after space
# Group by modules
echo "### $EDIT_TITLE " >> "$DOCFILE"
echo "ID: \`mint_system.$MODULE.$XML_ID.$EDIT\` " >> "$DOCFILE"
echo -e '```xml' >> "$DOCFILE"
cat "$FILE" >> "$DOCFILE"
echo -e '\n```' >> "$DOCFILE"
echo -e "Source: [$FILE]($PATH_URL/$FILE)\n" >> "$DOCFILE"
done
done
done
echo -e "export default [$SIDEBAR_ENTRIES]" > .vuepress/sidebar.js
}
function generate-revisions-doc() {
echo "Update revisions doc file."
rm -f "revisions.md"
echo -e "# Odoo Revisions \n\
A Odoo revision is a snapshot of git references of the Odoo source and modules at a specific date.\n\
For each major release there are multiple revisions.\n" > "revisions.md"
declare -A REVISIONS
PATH_URL="https://github.com/Mint-System/Odoo-Build/tree/16.0"
for FILE in scripts/odoo_revision_*; do
if [[ -f "$FILE" ]]; then
REVISION=$(basename "$FILE" | sed 's/odoo_revision_//')
VERSION=$(echo "$REVISION" | cut -d'.' -f1-2)
if [[ -z "${REVISIONS[$VERSION]}" ]]; then
REVISIONS[$VERSION]="## $VERSION"
fi
REVISIONS[$VERSION]+=$'\n\n'
REVISIONS[$VERSION]+="#### $REVISION"
REVISIONS[$VERSION]+=$'\n\n```bash\n'
REVISIONS[$VERSION]+=$(cat "$FILE")
REVISIONS[$VERSION]+=$'\n```'
fi
done
for REVISION in $(echo "${!REVISIONS[@]}" | tr ' ' '\n' | sort -V); do
echo -e "${REVISIONS[$REVISION]}\n" >> "revisions.md"
done
}
function generate-module-overview() {
echo "Update module overview doc file."
activate-venv
./scripts/generate_module_overview
}
function update-docs() {
generate-module-overview
generate-revisions-doc
generate-snippets-doc
generate-help-doc
}
# Module Commands
function get-modules() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
OPTION="$2"
if [ -z "$OPTION" ]; then
OPTION="dirname"
fi
if [[ "$OPTION" == "dirname" ]]; then
MODULES=$(echo "$1" | tr "," "\n" | xargs -I {} find {} -type f -name "__manifest__.py" | xargs grep -l "version.*${GIT_BRANCH}" | xargs -r dirname | sort -u | tr "\n" "," | sed 's/,$//')
fi
if [[ "$OPTION" == "basename" ]]; then
MODULES=$(echo "$1" | tr "," "\n" | xargs -I {} find {} -type f -name "__manifest__.py" | xargs grep -l "version.*${GIT_BRANCH}" | xargs -r dirname | xargs -r -I {} basename {} | sort -u | tr "\n" "," | sed 's/,$//')
fi
echo "$MODULES"
}
function get-module-version() {
if test -z "$1"
then
echo "\$1 is empty."
else
# Get version of module
VERSION=$(grep -m 1 \"version "$1/__manifest__.py" | sed "s;';\";g" | sed "s/,//g" | sed 's/#.*//g')
VERSION=$(echo "{ $VERSION }" | jq .version | sed 's/"//g' | sed 's/null//g')
# Set default version
[ -z "$VERSION" ] && VERSION=0.0
COUNT_DOTS=$(echo "$VERSION" | grep -o "\." | wc -l)
# Check if oca version or enterprise version
if [[ $COUNT_DOTS == 2 ]]; then
VERSION="$GIT_BRANCH.$VERSION"
fi
if [[ $COUNT_DOTS == 1 ]]; then
VERSION="$GIT_BRANCH.$VERSION"
fi
echo "$VERSION"
fi
}
function list-modules() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
echo $(get-modules "$1" basename | tr "," "\n")
}
# Container Commands
function template-docker-compose() {
echo "Template docker-compose.yml"
export CONTAINER_REGISTRY
export CONTAINER_TAG
export POSTGRES_PORT
export ODOO_PORT
export MAIL_DEFAULT_FROM
export MAIL_CATCHALL_DOMAIN
export MAIL_CATCHALL_ALIAS
export ODOO_MAIL_SMTP_HOST
export ODOO_MAIL_SMTP_PORT
export ODOO_MAIL_SMTP_ENCRYPTION
export ODOO_MAIL_SMTP_FROM_FILTER
export ODOO_MAIL_IMAP_HOST
export ODOO_MAIL_IMAP_PORT
export ODOO_MAIL_IMAP_SSL
export ODOO_MAIL_USERNAME
export ODOO_MAIL_PASSWORD
export GIT_SSH_PUBLIC_KEY
export GIT_SSH_PRIVATE_KEY
export ADDONS_GIT_REPOS
export ODOO_ADDONS_PATH
export ODOO_DATABASE
export ODOO_INIT
export ODOO_INIT_LANG
export ODOO_INIT_ADDONS
export ENVIRONMENT
export PYTHON_INSTALL
export SERVER_WIDE_MODULES
export SESSION_DB_URI
export PROXY_MODE
export LOG_LEVEL
export LIST_DB
export ADMIN_PASSWD
export DBFILTER
export WORKERS
export LIMIT_REQUEST
export LIMIT_TIME_CPU
export LIMIT_TIME_REAL
export MODULE_AUTO_INSTALL_DISABLED
export CLICK_ODOO_UPDATE
export PGADMIN_DEFAULT_EMAIL
export PGADMIN_DEFAULT_PASSWORD
export POSTGRES_IMAGE
envsubst < "docker-compose.yml.template" > "docker-compose.yml"
}
function ps() {
$CONTAINER_ENGINE ps
}
function build() {
MANIFEST_FILE="image/Dockerfile"
PLATFORM="linux/amd64" # linux/arm64
if [ -n "$1" ]; then
PLATFORM="$1"
fi
ODOO_DATE=""
if [[ "ODOO_REVISION" != "$GIT_BRANCH" ]]; then
ODOO_DATE=$(echo "$ODOO_REVISION" | cut -d'.' -f3-)
fi
echo "Remove container image with tag ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
$CONTAINER_ENGINE image rm -f "${CONTAINER_REGISTRY}${CONTAINER_TAG}"
if [ "$CONTAINER_ENGINE" == "podman" ]; then
echo "Run Podman build ${CONTAINER_REGISTRY}${CONTAINER_TAG} for ${PLATFORM}"
SOURCE_DATE_EPOCH=$(git -C odoo log -1 --pretty=%ct) podman build --platform "$PLATFORM" . \
--file "$MANIFEST_FILE" \
--build-arg ODOO_VERSION="$GIT_BRANCH" \
--build-arg ODOO_DATE="$ODOO_DATE" \
--tag "${CONTAINER_REGISTRY}${CONTAINER_TAG}"
fi
if [ "$CONTAINER_ENGINE" == "docker" ]; then
echo "Run Docker build ${CONTAINER_REGISTRY}${CONTAINER_TAG} for ${PLATFORM}"
SOURCE_DATE_EPOCH=$(git -C odoo log -1 --pretty=%ct) docker buildx build --platform "$PLATFORM" . \
--file "$MANIFEST_FILE" \
--build-arg ODOO_VERSION="$GIT_BRANCH" \
--build-arg ODOO_DATE="$ODOO_DATE" \
--tag "${CONTAINER_REGISTRY}${CONTAINER_TAG}" \
--load
fi
}
function container-login() {
echo "Setup container hub login credentials for $CONTAINER_REGISTRY"
echo -n "Enter username: "
read CONTAINER_REGISTRY_USERNAME
echo -n "Enter password: "
read -s CONTAINER_REGISTRY_PASSWORD
if [ "$CONTAINER_ENGINE" == "podman" ]; then
podman login --username "$CONTAINER_REGISTRY_USERNAME" --password "$CONTAINER_REGISTRY_PASSWORD" docker.io
fi
if [ "$CONTAINER_ENGINE" == "docker" ]; then
docker --config "$CONTAINER_CONFIG" login --username "$CONTAINER_REGISTRY_USERNAME" --password "$CONTAINER_REGISTRY_PASSWORD"
fi
}
function publish() {
LATEST_TAG="odoo:$GIT_BRANCH"
echo "Tag container image ${CONTAINER_REGISTRY}${CONTAINER_TAG} with ${CONTAINER_REGISTRY}${LATEST_TAG}"
$CONTAINER_ENGINE tag "${CONTAINER_REGISTRY}${CONTAINER_TAG}" "${CONTAINER_REGISTRY}${LATEST_TAG}"
if [ "$CONTAINER_ENGINE" == "docker" ]; then
echo "Push container image to ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
docker --config "$CONTAINER_CONFIG" push "${CONTAINER_REGISTRY}${CONTAINER_TAG}"
docker --config "$CONTAINER_CONFIG" push "${CONTAINER_REGISTRY}${LATEST_TAG}"
fi
}
function upload-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
# Check if path is root folder
MODULES="$2"
if [ ! -f "$2/__manifest__.py" ]; then
echo "Identified as root folder"
MODULES="$MODULES/*"
fi
for MODULE in $MODULES; do
if [ -f "$MODULE/__manifest__.py" ]; then
# Create module zip
zip-module "$MODULE"
# Get path to zip file and upload url
FILE_PATH="tmp/$MODULE_NAME.zip"
load-env "$1"
NEXTCLOUD_UPLOAD_URL="$NEXTCLOUD_URL/remote.php/dav/files/$NEXTCLOUD_USERNAME/Odoo-Apps/"
# Upload zip file
curl -u "$NEXTCLOUD_USERNAME:$NEXTCLOUD_PASSWORD" -T "$FILE_PATH" "$NEXTCLOUD_UPLOAD_URL"
echo "File $FILE_PATH uploaded to $NEXTCLOUD_UPLOAD_URL."
UPLOADS+=" - name: $MODULE\n"
UPLOADS+=" version: $VERSION\n"
fi
done
echo "odoo_apps:"
echo -e "$UPLOADS"
}
function logs() {
$CONTAINER_ENGINE logs --follow odoo
}
# Script Commands
function install-odoo-scripts() {
curl -L https://raw.githubusercontent.com/mint-system/ansible-build/master/roles/odoo_scripts/files/install | bash
}
function upgrade-odoo() {
if test -z "$1"; then echo "\$1/database is empty."; exit; fi
if test -z "$2"; then echo "\$2/version is empty."; exit; fi
DATABASE="$1"
ODOO_TARGET_VERSION="$2"
MODE="test"
if [ -n "$3" ]; then
# Options: test, production
MODE="$3"
fi
NEW_DATABASE="${DATABASE}_${ODOO_TARGET_VERSION}"
echo "Execute Odoo upgrade script in $MODE mode for $DATABASE with version $ODOO_TARGET_VERSION."
echo "The database will be restored as $NEW_DATABASE."
export PGHOST=localhost
export PGUSER=odoo
export PGPASSWORD=odoo
python <(curl -s https://upgrade.odoo.com/upgrade) "$MODE" -d "$DATABASE" -t "$ODOO_TARGET_VERSION" -r "$NEW_DATABASE"
echo "Upgrade finished successfully."
}
# Install Commands
function install-native() {
init-venv
activate-venv
if [[ "$OS_RELEASE" =~ ^(Ubuntu|Debian|Pop!_OS)$ ]]; then
# Source: https://gist.github.com/faniska/37f896d5e9de5fee925925d7caf3cb9e
INSTALLED_VERSION=$(wkhtmltopdf --version 2>&1 | grep -Po '^wkhtmltopdf \K[\d.]+')
if [ "$INSTALLED_VERSION" != "0.12.4" ]; then
echo "Install wkhtmltopdf"
sudo apt remove wkhtmltopdf
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
tar xvf wkhtmltox*.tar.xz
sudo mv wkhtmltox/bin/wkhtmlto* /usr/bin
rm -rf wkhtmltox wkhtmltox-0.12.4_linux-generic-amd64.tar.*
else
echo "wkhtmltopdf version is already 0.12.4"
fi
echo "Install python-ldap and psycopg2 build dependencies"
sudo apt-get install -y libsasl2-dev libldap2-dev libssl-dev libpq-dev python3-dev
echo "Install xmllint and gettext"
sudo apt install -y libxml2-utils gettext
elif [[ "$OS_RELEASE" =~ ^(Darwin)$ ]]; then
echo "Welcome daring Mac user. Let's try our best to get this working."
echo "Install wkhtmltopdf and some dev libraries"
echo "This will give a depreciation warning and you need to enter your sudo password."
brew install gettext wkhtmltopdf libsasl2 openldap openssl libxml2
echo "Install the binary version of psycopg2"
uv pip install psycopg2-binary --force
echo "Add LDFLAGS to .env file"
if ! grep -qxF 'LDFLAGS=-L/opt/homebrew/lib/' .env; then
echo '' >> .env
echo 'LDFLAGS=-L/opt/homebrew/lib/' >> .env
fi
else
echo "The operating system $OS_RELEASE is not supported."
exit 1
fi
echo "Install Odoo development tools"
uv pip install ${PYTHON_NOTIFY}
uv pip install -r requirements.txt
if [ -f "odoo/requirements.txt" ]; then
echo "Install Odoo dependencies"
uv pip install -r odoo/requirements.txt
echo "Configure Odoo as python package"
uv pip install pip
pip install -e odoo
fi
}
# Process Commands
function open-url-with-delay(){
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if $BROWSER_OPEN; then
sleep 2
$OS_OPEN "$1"
fi
}
function start() {
activate-venv
set-addons-path
template-docker-compose
# Use default database if second param is not given
DATABASE="$2"
if [ -z "$2" ]; then
DATABASE="$ODOO_DATABASE"
fi
if [ -z "$1" ] ; then
echo "Start odoo container ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
echo "Open http://localhost:8069 url in your browser."
$COMPOSE_COMMAND up -d
fi
if [[ "$1" =~ "db" ]]; then
$COMPOSE_COMMAND up -d db
fi
if [[ "$1" =~ "admin" ]]; then
echo "Open http://localhost:8000 url in your browser."
open-url-with-delay "http://localhost:8000" & $COMPOSE_COMMAND up -d admin
fi
if [[ "$1" =~ "odoo" ]]; then
echo "Start odoo container ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
echo "Open http://localhost:8069 url in your browser."
open-url-with-delay "http://localhost:8069" & $COMPOSE_COMMAND up -d odoo
fi
if [[ "$1" =~ "native" ]]; then
activate-venv
template-odoo-rc
PORT=8069
while [ $PORT -le 8079 ]; do
if ! lsof -i:$PORT >/dev/null 2>&1; then
break
fi
PORT=$((PORT + 1))
done
export ODOO_BASE_URL="http://localhost:8069"
echo "Open http://localhost:$PORT url in your browser."
open-url-with-delay "http://localhost:$PORT/web?debug=1&db=$DATABASE" &
odoo --database="$DATABASE" --config "$ODOO_RC" --xmlrpc-port="$PORT" --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL"
fi
if [[ "$1" =~ "queue" ]]; then
activate-venv
PORT=8069
echo "Open http://localhost:$PORT url in your browser."
open-url-with-delay "http://localhost:$PORT/web?debug=1&db=$DATABASE" &
odoo --database="$DATABASE" --config "$ODOO_RC" --xmlrpc-port="$PORT" --gevent-port=8072 --load=web,queue_job --workers=4 --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL" --log-handler=odoo.addons.queue_job:DEBUG
fi
if [[ "$1" =~ "mail" ]]; then
echo "Open http://localhost:8025 url in your browser."
open-url-with-delay "http://localhost:8025" & $COMPOSE_COMMAND up -d mail
fi
}
function remove() {
activate-venv
template-docker-compose
if test -z "$1"; then
$COMPOSE_COMMAND down -v
fi
if [[ "$1" =~ "db" ]]; then
$COMPOSE_COMMAND rm -f -s -v db
fi
if [[ "$1" =~ "admin" ]]; then
$COMPOSE_COMMAND rm -f -s -v admin
fi
if [[ "$1" =~ "odoo" ]]; then
$COMPOSE_COMMAND rm -f -s -v odoo
fi
if [[ "$1" =~ "mail" ]]; then
$COMPOSE_COMMAND rm -f -s -v mail
fi
}
function restart() {
activate-venv
template-docker-compose
if test -z "$1"; then
$COMPOSE_COMMAND restart
fi
if [[ "db|mail|odoo" =~ $1 ]]; then
$COMPOSE_COMMAND restart "$1"
fi
}
function stop() {
activate-venv
template-docker-compose
if test -z "$1"; then
$COMPOSE_COMMAND stop
fi
$COMPOSE_COMMAND stop "$1"
}
function test-container() {
activate-venv
version
info
if [ -z "$GIT_SSH_PRIVATE_KEY" ]; then
echo "Generate SSH private key."
mkdir -p tmp
if [ ! -f "tmp/ed25519" ]; then
ssh-keygen -t ed25519 -C admin@example.com -f tmp/ed25519 -N ""
fi
GIT_SSH_PRIVATE_KEY=$(cat tmp/ed25519 | base64 -w0)
GIT_SSH_PUBLIC_KEY=$(cat tmp/ed25519.pub)
fi
echo "Clone submodule"
git submodule update --init oca/partner-contact
echo "Start container environment."
export GIT_SSH_PRIVATE_KEY
export GIT_SSH_PUBLIC_KEY
export ADDONS_GIT_REPOS="https://github.com/OCA/server-env.git#${GIT_BRANCH},https://github.com/OCA/server-tools.git#${GIT_BRANCH},https://github.com/Mint-System/Odoo-Apps-Server-Tools.git#${GIT_BRANCH},https://github.com/Mint-System/Odoo-Apps-Connector.git#${GIT_BRANCH}"
export ODOO_ADDONS_PATH="/mnt/enterprise,/mnt/oca"
export ODOO_DATABASE=test
export ODOO_INIT=True
export ODOO_INIT_LANG=de_CH
export ODOO_INIT_ADDONS=server_environment_ir_config_parameter,module_auto_update,prometheus_exporter,mail_server_filter,git_base,contacts,web_enterprise
export PYTHON_INSTALL=prometheus-client,manifestoo
export SERVER_WIDE_MODULES=web,session_db,module_change_auto_install
export SESSION_DB_URI=postgres://odoo:odoo@db/test
export MODULE_AUTO_INSTALL_DISABLED=odoo_test_xmlrunner
export CLICK_ODOO_UPDATE=True
export ODOO_MAIL_SMTP_HOST=mail
export ODOO_MAIL_SMTP_PORT=1025
export ODOO_MAIL_SMTP_ENCRYPTION=none
export MAIL_DEFAULT_FROM="test"
export BROWSER_OPEN=false
start db,odoo,mail
while ! curl --fail -s http://localhost:8069; do sleep 1; done
echo "Test auto upgrade."
docker-odoo-init -d test -i partner_firstname
sed -i -E 's/(firstname = fields)/secondname = fields.Char();\1/' oca/partner-contact/partner_firstname/models/res_partner.py
restart odoo
while ! curl --fail -s http://localhost:8069; do sleep 1; done
echo "Check if auto upgrade was successful."
scripts/odooctl --method "search_one" --model "ir.model.fields" --domain "[('name', '=', 'secondname')]"
echo "Setup and test RPC credentials."
export ODOO_URL="http://localhost:8069"
export ODOO_USERNAME=admin
export ODOO_PASSWORD=admin
create-odoo-env test
show-env test
test-xmlrpc test
echo "Send mail with message post."
echo "Install, update, disable and remove snippet."
install-snippet test snippets/base.view_partner_form.show_type.xml
update-snippet test snippets/base.view_partner_form.show_type.xml
disable-snippet test snippets/base.view_partner_form.show_type.xml
remove-snippet test snippets/base.view_partner_form.show_type.xml
echo "Test Odoo scripts."
docker-odoo-backup -d test
docker-odoo-drop -d test
docker-odoo-restore -d test -f /var/tmp/test.zip
change-uuid test
echo "Cleanup test environment."
remove-env test
git -C oca/partner-contact checkout .
}
# Kubernetes Commands
function start-kind() {
echo "Start kind."
kind create cluster
}
function start-minikube() {
echo "Start minikube."
minikube start
}
function k8s-apply() {
echo "Deploy Postgres:"
kubectl apply -f k8s/postgres-cm.yaml
kubectl apply -f k8s/postgres-pvc.yaml
kubectl apply -f k8s/postgres-deploy.yaml
kubectl apply -f k8s/postgres-svc.yaml
echo -e "\nDeploy Odoo:"
kubectl apply -f k8s/odoo-cm.yaml
kubectl apply -f k8s/odoo16-deploy.yaml
kubectl apply -f k8s/odoo-svc.yaml
echo -e "\nWait until resources are ready."
sleep 8
ODOO_POD=$(kubectl get pods -o=name --all-namespaces | grep odoo)
POSTGRES_POD=$(kubectl get pods -o=name --all-namespaces | grep postgres)
echo -e "\nWait for $ODOO_POD and $POSTGRES_POD pods to be running:"
kubectl wait --for=condition=Ready "$ODOO_POD" "$POSTGRES_POD" --timeout=60s
sleep 3
echo -e "\nInit Odoo database in $ODOO_POD pod:"
kubectl exec "$ODOO_POD" -- env
kubectl exec "$ODOO_POD" -- /bin/bash -c "odoo -d odoo -i web --db_host \$HOST -r\$USER -w\$PASSWORD --stop-after-init --no-http"
}
function test-k8s() {
start-kind
k8s-apply
}
# Interactive Shell Commands
function start-shell() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
activate-venv
set-addons-path
odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}
function start-psql() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
$CONTAINER_ENGINE exec -it db psql "postgres://odoo:odoo@localhost:5432/$DATABASE"
}
# Database Commands
function init-db() {
ODOO_INIT_ADDONS="${ODOO_INIT_ADDONS:-"web"}"
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
activate-venv
set-addons-path
template-odoo-rc
echo "Initialize database $DATABASE with $ODOO_INIT_ADDONS."
if [[ -n "$ODOO_PARAM" ]]; then
odoo -d "$DATABASE" -i "$ODOO_INIT_ADDONS" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$ODOO_LANGUAGE" "$ODOO_PARAM"
else
odoo -d "$DATABASE" -i "$ODOO_INIT_ADDONS" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$ODOO_LANGUAGE"
fi
}
function import-csv() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
FILE_PATH="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
FILE_PATH="$1"
fi
FILE_NAME=$(basename "$FILE_PATH")
echo "Importing $FILE_NAME to $DATABASE ..."
$CONTAINER_ENGINE cp "$FILE_PATH" db:/tmp/
$CONTAINER_ENGINE exec db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "\copy $FILE_NAME FROM '/tmp/$FILE_NAME' DELIMITER ',' CSV HEADER;"
}
function drop-db() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DATABASE';"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "DROP DATABASE \"$DATABASE\";"
}
function setup-mail() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
activate-venv
set-addons-path
PYTHON_SCRIPT=$(envsubst < scripts/setup-mail)
echo "Setup mail server configuation for database $DATABASE."
echo "$PYTHON_SCRIPT" | odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}
function setup-mail-sql() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
activate-venv
set-addons-path
if [ -n "$ODOO_MAIL_SMTP_HOST" ]; then
ODOO_MAIL_SMTP_PORT=${ODOO_MAIL_SMTP_PORT:="587"}
ODOO_MAIL_SMTP_ENCRYPTION=${ODOO_MAIL_SMTP_ENCRYPTION:="starttls"}
ODOO_MAIL_SMTP_FROM_FILTER=${ODOO_MAIL_SMTP_FROM_FILTER:=""}
IR_MAIL_SERVER_ID=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT id FROM ir_mail_server WHERE name = '$ODOO_MAIL_SMTP_HOST' LIMIT 1")
if [ -z "$IR_MAIL_SERVER_ID" ]; then
echo "Setup outgoing mail server $ODOO_MAIL_SMTP_HOST for database $DATABASE."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "INSERT INTO ir_mail_server (active, name, smtp_host, smtp_port, smtp_user, smtp_pass, smtp_encryption, from_filter, smtp_authentication) VALUES (TRUE, '$ODOO_MAIL_SMTP_HOST', '$ODOO_MAIL_SMTP_HOST', $ODOO_MAIL_SMTP_PORT, '$ODOO_MAIL_USERNAME', '$ODOO_MAIL_PASSWORD', '$ODOO_MAIL_SMTP_ENCRYPTION', '$ODOO_MAIL_SMTP_FROM_FILTER', 'login')"
fi
fi
if [ -n "$ODOO_MAIL_IMAP_HOST" ]; then
ODOO_MAIL_IMAP_PORT=${ODOO_MAIL_IMAP_PORT:="993"}
ODOO_MAIL_IMAP_SSL=${ODOO_MAIL_IMAP_SSL:="True"}
FETCHMAIL_SERVER_ID=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT id FROM fetchmail_server WHERE name = '$ODOO_MAIL_SMTP_HOST' LIMIT 1")
if [ -z "$FETCHMAIL_SERVER_ID" ]; then
echo "Setup incoming mail server $ODOO_MAIL_IMAP_HOST for database $DATABASE."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "INSERT INTO fetchmail_server (\"active\", \"name\", \"server\", \"port\", \"user\", \"password\", \"is_ssl\", \"server_type\", \"state\") VALUES (TRUE, '$ODOO_MAIL_SMTP_HOST', '$ODOO_MAIL_IMAP_HOST', $ODOO_MAIL_IMAP_PORT, '$ODOO_MAIL_USERNAME', '$ODOO_MAIL_PASSWORD', $ODOO_MAIL_IMAP_SSL, 'imap', 'done')"
fi
fi
if [ -n "$MAIL_CATCHALL_ALIAS" ]; then
MAIL_CATCHALL_ALIAS_VALUE=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT value FROM ir_config_parameter WHERE key = 'mail.catchall.alias'")
if [ "$MAIL_CATCHALL_ALIAS_VALUE" != "$MAIL_CATCHALL_ALIAS" ]; then
echo "Update system parameter mail.catchall.alias with value $MAIL_CATCHALL_ALIAS."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE ir_config_parameter SET value = '$MAIL_CATCHALL_ALIAS' WHERE key = 'mail.catchall.alias'"
fi
fi
if [ -n "$MAIL_DEFAULT_FROM" ]; then
MAIL_DEFAULT_FROM_VALUE=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT value FROM ir_config_parameter WHERE key = 'mail.default.from'")
if [ "$MAIL_DEFAULT_FROM_VALUE" != "$MAIL_DEFAULT_FROM" ]; then
echo "Update system parameter mail.default.from with value $MAIL_DEFAULT_FROM."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE ir_config_parameter SET value = '$MAIL_DEFAULT_FROM' WHERE key = 'mail.default.from'"
fi
fi
if [ -n "$MAIL_CATCHALL_DOMAIN" ]; then
MAIL_CATCHALL_DOMAIN_KEY=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT id FROM ir_config_parameter WHERE key = 'mail.catchall.domain'")
if [ -z "$MAIL_CATCHALL_DOMAIN_KEY" ]; then
echo "Add system parameter mail.catchall.domain with value $MAIL_CATCHALL_DOMAIN."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "INSERT INTO ir_config_parameter (key, value) VALUES ('mail.catchall.domain', '$MAIL_CATCHALL_DOMAIN')"
fi
MAIL_CATCHALL_DOMAIN_VALUE=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT value FROM ir_config_parameter WHERE key = 'mail.catchall.domain'")
if [ "$MAIL_CATCHALL_DOMAIN_VALUE" != "$MAIL_CATCHALL_DOMAIN" ]; then
echo "Update system parameter mail.catchall.domain with value $MAIL_CATCHALL_DOMAIN."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE ir_config_parameter SET value = '$MAIL_CATCHALL_DOMAIN' WHERE key = 'mail.catchall.domain'"
fi
fi
}
function load-language() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
LANGUAGE="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
LANGUAGE="$1"
fi
activate-venv
set-addons-path
echo "Setup language $LANGUAGE for database $DATABASE:"
odoo -d "$DATABASE" -u all --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$LANGUAGE"
}
function set-admin() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE res_users SET active=true,password='\$pbkdf2-sha512\$25000\$JuScEwIg5JzTGqNUivFeqw\$yWTOcix2Afr3XGP2NPY7w4w49e9vpsu14NRndDYXAkbtMF4zkrmx6inVsoLl0zZY30xI/0GzhwonWsK9TUmjWA' WHERE id=2;"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "SELECT login, password FROM res_users WHERE id=2;"
}
function clear-assets() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
echo "Delete these assets for $DATABASE:"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "select id,name from ir_attachment where res_model='ir.ui.view' and name like '%assets_%';"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "delete from ir_attachment where res_model='ir.ui.view' and name like '%assets_%';"
}
function clear-views() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
echo "Archive views with prefix 'mint_system'."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "SELECT id,name from ir_ui_view WHERE name like '%mint_system%';"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "UPDATE ir_ui_view SET active=false WHERE name like '%mint_system%';"
echo "Archive views with prefix 'Odoo Studio:'."
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "SELECT id,name from ir_ui_view WHERE name like '%Odoo Studio:%';"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "UPDATE ir_ui_view SET active=false WHERE name like '%Odoo Studio:%';"
echo "Delete all active views for $DATABASE in $CONTAINER :"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "DELETE FROM report_layout WHERE view_id IN (SELECT id FROM ir_ui_view WHERE active = TRUE);"
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "WITH RECURSIVE views_to_delete AS (SELECT id, inherit_id FROM ir_ui_view WHERE active = TRUE AND inherit_id IS NULL UNION ALL SELECT v.id, v.inherit_id FROM ir_ui_view v JOIN views_to_delete p ON v.inherit_id = p.id) DELETE FROM ir_ui_view WHERE id IN (SELECT id FROM views_to_delete);"
}
function convert-database() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
unzip "tmp/$1.zip" -d "./tmp/$1"
sed -i'' 's/AS integer//g' "./tmp/$1/dump.sql"
grep -i 'as integer' "./tmp/$1/dump.sql"
cd "tmp/$1" || exit ; zip -r "../${1}2.zip" . ; cd ../.. || exit
rm -r "tmp/$1"
echo "Converted database file $1 to ${1}2"
}
function clear-filestore() {
echo "Remove directory $HOME/.local/share/Odoo/filestore/$1"
rm -rf "$HOME/.local/share/Odoo/filestore/$1"
}
function disable-mailserver() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
activate-venv
load-env "$1"
scripts/odooctl --method 'write' --model 'ir.mail_server' --field 'active' --value False --domain "[]"
scripts/odooctl --method 'write' --model 'fetchmail.server' --field 'active' --value False --domain "[]"
}
function change-uuid() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
activate-venv
load-env "$1"
UUID=$(uuidgen)
echo "Set uuid $UUID for $1."
scripts/odooctl --method 'write' --model 'ir.config_parameter' --domain "[('key', '=', 'database.uuid')]" --field 'value' --value "'$UUID'"
}
function update-app-list() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
activate-venv
set-addons-path
echo "env['ir.module.module'].update_list()" | odoo shell --database "$1" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}
function patch-database() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
FILENAME="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
FILENAME="$1"
fi
echo "Apply patch $FILENAME to Database $DATABASE."
cat "$FILENAME" | $CONTAINER_ENGINE exec -i db psql "postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost/$DATABASE"
echo "Patching database succeeded"
}
function save-config() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
activate-venv
set-addons-path
odoo -d "$DATABASE" -s --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
}
# Report Commands
function odoo-cloc() {
DATABASE="$1"
if [ -z "$DATABASE" ]; then
DATABASE="$ODOO_DATABASE"
fi
activate-venv
set-addons-path
odoo cloc -d "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
}
function visualize-dependencies() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
MODULE_DIR="$1"
OUTPUT_FILE="tmp/module_dependencies.mmd"
mkdir -p tmp
echo "graph TD" > "$OUTPUT_FILE"
for MODULE_PATH in "$MODULE_DIR"/*; do
if [[ -d "$MODULE_PATH" ]]; then
MODULE_NAME=$(basename "$MODULE_PATH")
MANIFEST_FILE="$MODULE_PATH/__manifest__.py"
if [[ -f $MANIFEST_FILE ]]; then
DEPENDENCIES=$(grep -Po '(?<="depends": \[)[^\]]*' "$MANIFEST_FILE" | tr -d '"[] ')
if [[ -n "$DEPENDENCIES" ]]; then
for DEPENDENCY in $(echo "$DEPENDENCIES" | tr ',' '\n'); do
echo " $MODULE_NAME --> $DEPENDENCY" >> "$OUTPUT_FILE"
done
fi
fi
fi
done
echo "Mermaid output generated: $OUTPUT_FILE"
echo "Run mermaid-cli with npx and open png file ..."
npx @mermaid-js/mermaid-cli -i $OUTPUT_FILE -o tmp/module_dependencies.png --scale 10
$OS_OPEN tmp/module_dependencies.png
}
# Module Development Commands
function install-requirements() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
FILE_PATH="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
FILE_PATH="$1"
fi
FILE_NAME=$(basename "$FILE_PATH")
if [[ "$FILE_NAME" != "requirements.txt" ]]; then echo "\$1 must point to requirements.txt file."; exit; fi
CONTAINER_RUNNING=$($CONTAINER_ENGINE container inspect -f '{{.State.Running}}' odoo)
if [ "$CONTAINER_RUNNING" == "true" ]; then
echo "Installing python packages in container ..."
$CONTAINER_ENGINE exec -u root odoo python -m pip install -r "/mnt/$FILE_PATH"
else
activate-venv
echo "Installing python packages in virutal env ..."
uv pip install -r "$FILE_PATH"
fi
}
function init-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
MODULE_PATH="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_PATH="$1"
fi
# Check if module path is a module repo
if [ -f "$MODULE_PATH/README.md" ]; then
# Look for manifest files in repo folder
# Get parent folder name of manifest files
# Create a comma separated string of folder names
MODULES=$(get-modules "$MODULE_PATH" basename)
else
MODULES=$(basename "$MODULE_PATH")
fi
activate-venv
set-addons-path
echo "Initialize module $MODULES on $DATABASE ..."
odoo -d "$DATABASE" -i "$MODULES" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
}
function upgrade-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
activate-venv
echo "Upgrade code of module $1 from $2 ..."
odoo upgrade_code --addons-path "$1" --from "$2"
}
function update-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
MODULE_NAME=$(basename "$2")
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_NAME=$(basename "$1")
fi
activate-venv
set-addons-path
echo "Updating module $MODULE_NAME on $DATABASE ..."
if [[ -n "$ODOO_PARAM" ]] ; then
odoo --database "$DATABASE" --update "$MODULE_NAME" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http "$ODOO_PARAM"
else
odoo --database "$DATABASE" --update "$MODULE_NAME" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
fi
}
function translate-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
MODULE_PATH="$2"
MODULE_NAME=$(basename "$2")
LANGUAGE="$3"
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_PATH="$1"
MODULE_NAME=$(basename "$1")
fi
if test -z "$3"; then
LANGUAGE="$ODOO_LANGUAGE"
fi
activate-venv
set-addons-path
echo "Generate $LANGUAGE tranlsation file for $MODULE_NAME on $DATABASE ..."
mkdir -p "$MODULE_PATH/i18n/"
odoo -d "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --modules "$MODULE_NAME" -l "$LANGUAGE" --i18n-export "$MODULE_PATH/i18n/$LANGUAGE.po"
# if lang is de_CH then rename the file to de.po.
if [[ "$LANGUAGE" == "de_CH" ]]; then
mv "$MODULE_PATH/i18n/$LANGUAGE.po" "$MODULE_PATH/i18n/de.po"
fi
}
function lint-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
activate-venv
echo "Set file and folder permissions on $1"
find "$1" -type d -exec chmod u=rwx,go=rx {} \;
find "$1" -type f -exec chmod u=rw,go=r {} \;
echo "Update index.html"
rst2html5 "$1/README.rst" "$1/static/description/index.html"
pushd .
cd "$1"
echo "Run pre-commit in $PWD"
pre-commit run --all-files # --show-diff-on-failure --color=always
echo "Stage changes"
git add .
popd
}
function lint-module-repo() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
MODULE_PATHS=$(get-modules "$MODULE_PATH")
for MODULE_PATH in ${MODULE_PATHS//,/ }; do
lint-module "$MODULE_PATH"
done
}
function test-module() {
DATABASE="$1"
MODULE_NAME=$(basename "$2")
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_NAME=$(basename "$1")
fi
activate-venv
set-addons-path
echo "Testing module $MODULE_NAME on $DATABASE ..."
odoo -d "$DATABASE" -i "$MODULE_NAME" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --test-tags /"$MODULE_NAME"
}
function test-module-repo() {
DATABASE="$1"
MODULE_PATH="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_PATH="$1"
fi
MODULES=$(get-modules "$MODULE_PATH" basename)
for MODULE in ${MODULES//,/ }; do
echo "Testing module $MODULE ..."
test-module "$DATABASE" "$MODULE"
done
}
function pytest-module() {
DATABASE="$1"
MODULE_PATH="$2"
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_PATH="$1"
fi
activate-venv
set-addons-path
ODOO_CONFIG="tmp/odoo.conf"
echo "Write $ODOO_CONFIG"
echo "[options]" > "$ODOO_CONFIG"
echo "addons_path=$ADDONS_PATH" >> "$ODOO_CONFIG"
echo "db_host = localhost" >> "$ODOO_CONFIG"
echo "db_password = odoo" >> "$ODOO_CONFIG"
echo "db_user = odoo" >> "$ODOO_CONFIG"
pytest -s --odoo-http --odoo-config="$ODOO_CONFIG" --odoo-database="$DATABASE" "$MODULE_PATH"
}
function remove-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
MODULE_NAME=$(basename "$2")
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
MODULE_NAME=$(basename "$1")
fi
activate-venv
set-addons-path
echo "Remove module $MODULE_NAME"
echo "self.env['ir.module.module'].search([('name', '=', '$MODULE_NAME')]).button_immediate_uninstall()" |
odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}
function create-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
MODULE_NAME=$(basename "$1")
PARENT_DIR=$(dirname "$1")
activate-venv
echo "Scaffolding module $MODULE_NAME in $PARENT_DIR ..."
odoo scaffold "$MODULE_NAME" "$PARENT_DIR" -t templates/module
}
function create-module-repo() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
REPO_PATH="$1"
REPO_NAME=$(basename "$REPO_PATH")
# If repo already exists, create new branch
if [ -d "$REPO_PATH/.git" ]; then
echo "Create new branch $REPO_NAME in $REPO_PATH"
cd "$REPO_PATH" || exit
git switch --orphan -c "$GIT_BRANCH"
echo "Remove all files from $REPO_PATH"
rm -rf "$REPO_PATH/*"
fi
echo "Copy template files from templates/GIT_BRANCH to $REPO_PATH"
cp templates/GIT_BRANCH/* "$REPO_PATH"
}
function generate-module-security() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
MODULE_NAME=$(basename "$1")
PARENT_DIR=$(dirname "$1")
MODEL_DOT_NAME="$2"
MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_')
ACCESS_FILE="$PARENT_DIR/$MODULE_NAME/security/ir.model.access.csv"
mkdir -p "$PARENT_DIR/$MODULE_NAME/security"
if [ ! -f "$ACCESS_FILE" ]; then
echo "Init security file: $ACCESS_FILE"
echo "id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink" > "$ACCESS_FILE"
fi
# id
# name
# model_id:id
# group_id:id
# perm_read
# perm_write
# perm_create
# perm_unlink
echo "Add model access to $ACCESS_FILE"
echo "access_${MODEL_NAME}_user,access.$MODEL_DOT_NAME.user,model_${MODEL_NAME},base.group_user,1,0,0,0" >> "$ACCESS_FILE"
echo "access_${MODEL_NAME}_manager,access.$MODEL_DOT_NAME.manager,model_${MODEL_NAME},base.group_erp_manager,1,1,1,1" >> "$ACCESS_FILE"
}
function generate-module-model() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
MODULE_PATH="$1"
MODULE_NAME=$(basename "$1")
# Generate template values
MODEL_DOT_NAME="$2" # res.partner
MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_') # res_partner
NAME=$(echo "$MODEL_DOT_NAME" | cut -d"." -f2 | sed 's/[^_]\+/\L\u&/g') # Partners
MODEL_DESCRIPTION=$(echo "$MODEL_NAME" | sed 's/[^_]\+/\L\u&/g' | sed 's/_/ /g') # Res Partner
MODEL_CAMEL_NAME=$(echo "$MODEL_DESCRIPTION" | sed 's/ //g') # ResPartner
export NAME MODULE_NAME MODEL_DOT_NAME MODEL_NAME MODEL_DESCRIPTION MODEL_CAMEL_NAME
echo "Substitute model template"
envsubst '$NAME $MODULE_NAME $MODEL_DOT_NAME $MODEL_NAME $MODEL_DESCRIPTION $MODEL_CAMEL_NAME' < templates/model.py > "$MODULE_PATH/models/$MODEL_NAME.py"
echo "from . import $MODEL_NAME" >> "$MODULE_PATH/models/__init__.py"
echo "Substitute view template"
mkdir -p "$MODULE_PATH/views"
envsubst '$NAME $MODULE_NAME $MODEL_DOT_NAME $MODEL_NAME $MODEL_DESCRIPTION $MODEL_CAMEL_NAME' < templates/model_views.xml > "$MODULE_PATH/views/${MODEL_NAME}_views.xml"
echo "Update file $MODULE_NAME/__manifest__.py with:"
echo -e "\t\"views/${MODEL_NAME}_views.xml\","
}
function generate-module-snippet() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
MODULE_PATH="$1"
VIEW_REF="$2"
# Generate template values
MODEL_NAME="crm_lead"
MODEL_DOT_NAME="crm.lead"
MODULE_NAME=$(basename "$1")
SRC_MODULE_NAME=$(echo "$VIEW_REF" | cut -d"." -f1)
XML_ID=$(echo "$VIEW_REF" | cut -d"." -f1)
export MODULE_NAME MODEL_DOT_NAME SRC_MODULE_NAME XML_ID
echo "Substitute snippet template"
envsubst '$MODULE_NAME $MODEL_DOT_NAME $SRC_MODULE_NAME $XML_ID' < templates/model_snippet.xml > "$MODULE_PATH/views/$MODEL_NAME_views.xml"
echo "Update file $MODULE_NAME/__manifest__.py with:"
echo -e "\t, \"views/${MODEL_NAME}_views.xml\""
}
function release-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
VERSION=$(get-module-version "$1")
cd "$1" || exit
LAST_TAG=$(git describe --tags)
RELEASE_NOTES=$(git log "$LAST_TAG"..HEAD --oneline)
echo "Tag with v$VERSION ..."
git tag -a "v$VERSION" -m "v$VERSION"
echo "Release notes:"
echo "$RELEASE_NOTES"
}
function zip-module() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
# Get version and module name
VERSION=$(get-module-version "$1")
MODULE=$(basename "$1")
# Copy module to tmp folder
echo "Copy module $MODULE version $VERSION to tmp folder"
MODULE_NAME="$MODULE-$VERSION"
MODULE_PATH="tmp/$MODULE_NAME"
rm -rf "$MODULE_PATH"
mkdir -p "$MODULE_PATH"
cp -r "$1/." "$MODULE_PATH"
find "$MODULE_PATH" -type d -exec chmod u=rwx,go=rx {} \;
find "$MODULE_PATH" -type f -exec chmod u=rw,go=r {} \;
# Configure and zip module
echo "Remove auto install option"
sed -i'' -e "s/'auto_install': True,/'auto_install': False,/" "$MODULE_PATH/__manifest__.py"
echo "Remove pycache and hidden folders"
find "$MODULE_PATH" | grep -E "(\.git|__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
echo "Zip module $MODULE"
cd tmp || exit
rm -f "$MODULE_NAME".zip
zip -q -r "$MODULE_NAME".zip "$MODULE_NAME"
cd .. || exit
}
# Snippet Commands
function reset-views() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
DATABASE="$1"
KEY=$(basename "$2")
# Use default database if second param is not given
if test -z "$2"; then
DATABASE="$ODOO_DATABASE"
KEY=$(basename "$1")
fi
activate-venv
set-addons-path
echo "Reset views for key $KEY"
echo "self.env['ir.ui.view'].search([('key', 'ilike', '$KEY')]).reset_arch(mode='hard')" |
odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}
function create-snippet() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
export INHERIT_ID=$(echo "$1" | cut -d. -f1-2)
FILE="snippets/$1.xml"
echo "Create snippet from template: $FILE"
envsubst '$INHERIT_ID' < templates/snippet.xml > "$FILE"
}
function install-snippet() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
# Generate view name from filename
FILE=$(basename "$2")
NAME="mint_system.${FILE%.xml}"
INHERIT_ID=$(echo 'cat //data/@inherit_id' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
TYPE=$(echo 'cat //data/@type' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
MODEL=$(echo 'cat //data/@model' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
PRIORITY=$(echo 'cat //data/@priority' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
MODULE_NAME=$(echo "$INHERIT_ID" | cut -d. -f 1 )
XML_ID=$(echo "$INHERIT_ID" | cut -d. -f 2 )
# Set default values
: ${TYPE:='qweb'}
activate-venv
load-env "$1"
echo "Search for view with name $MODULE_NAME.$XML_ID"
INHERIT_ID=$(scripts/odooctl --method "read" --model "ir.model.data" --field "res_id" --domain "[('name', '=', '$XML_ID'), ('module', '=', '$MODULE_NAME')]")
echo "Found view id $INHERIT_ID"
echo "Apply view $NAME"
scripts/odooctl --method 'create' --model 'ir.ui.view' --value "{
'name': '$NAME',
'type': '$TYPE',
'model': '$MODEL',
'mode': 'extension',
'priority': $PRIORITY,
'inherit_id': $INHERIT_ID,
'arch_base': '''$(cat "$2")'''
}"
}
function update-snippet() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
# Generate view name from filename
FILE=$(basename "$2")
NAME="mint_system.${FILE%.xml}"
activate-venv
load-env "$1"
echo "Update view with name $NAME"
scripts/odooctl --method 'write' --model 'ir.ui.view' --domain "[('name', '=', '$NAME')]" --field 'arch_base' --value "'''$(cat "$2")'''"
}
function disable-snippet() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
# Generate view name from filename
FILE=$(basename "$2")
NAME="mint_system.${FILE%.xml}"
activate-venv
load-env "$1"
echo "Disable view with name $NAME"
scripts/odooctl --method 'write' --model "ir.ui.view" --domain "[('name', '=', '$NAME')]" --field "active" --value "False"
}
function remove-snippet() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
# Generate view name from filename
FILE=$(basename "$2")
NAME="mint_system.${FILE%.xml}"
activate-venv
load-env "$1"
echo "Remove view with name $NAME"
scripts/odooctl --method "unlink" --model "ir.ui.view" --domain "[('name', '=', '$NAME')]"
}
function lint-snippets() {
echo "Lint snippets files ..."
FILES="snippets/*.xml"
for FILE in $FILES; do
# Access various snippet parameters
FILENAME=$(basename "$FILE")
SNIPPET_MODULE=$(echo "$FILENAME" | cut -d. -f1)
REPORT=$(echo "$FILENAME" | cut -d. -f2)
EDIT=$(echo "$FILENAME" | cut -d. -f3)
INHERIT_ID=$(echo 'cat //data/@inherit_id' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
TYPE=$(echo 'cat //data/@type' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
MODEL=$(echo 'cat //data/@model' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
PRIORITY=$(echo 'cat //data/@priority' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
MODULE_NAME=$(echo "$INHERIT_ID" | cut -d. -f 1 )
XML_ID=$(echo "$INHERIT_ID" | cut -d. -f 2 )
# Check filename
COUNT_DOTS=$(echo "$FILENAME" | grep -o "\." | wc -l)
if [ "$COUNT_DOTS" -ge 4 ]; then
echo "Linting failed for $FILE"
echo "Dots count: $COUNT_DOTS"
echo " Filename: $SNIPPET_MODULE.$REPORT"
exit 1
fi
# Check if inherit id matches the filename
if [ -n "$INHERIT_ID" ]; then
if [[ "$INHERIT_ID" != "$SNIPPET_MODULE.$REPORT" ]]; then
echo "Linting failed for $FILE"
echo " Inherit: $INHERIT_ID"
echo "Filename: $SNIPPET_MODULE.$REPORT"
exit 1
fi
fi
# Check if priority is set
if [ -z "$PRIORITY" ] && [ -n "$INHERIT_ID" ]; then
echo "Linting failed for $FILE"
echo "No priority is set."
exit 1
fi
done
echo "No problems with snippets found."
}
# Git Commands
function git-fetch() {
git fetch origin 13.0
git fetch origin 14.0
git fetch origin 15.0
git fetch origin 16.0
git fetch origin 17.0
git fetch origin 18.0
}
function git-submodule-add() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
if test -z "$2"; then echo "\$2 is empty."; exit; fi
git submodule add -f -b "$GIT_BRANCH" "$1" "$2"
}
function git-submodule-ls() {
echo $(git config --file .gitmodules --get-regexp url | sed -e 's/submodule.//g' -e 's/.url.*//g')
}
function git-submodule-list() {
# git submodule foreach --quiet 'printf "%-30s %-20s\n" "$name" "$(git rev-parse --abbrev-ref HEAD)"'
git config --file .gitmodules --get-regexp url | sed -e 's/submodule.//g' -e 's/.url//g' | awk '{ print $1 "," $2}'
}
function git-submodule-delete() {
echo "Delete git submodules."
# Using "git submodule update --init --recursive" is not possible as modules are registered from different branches
SUBMODULES=$(git-submodule-ls)
for SUBMODULE in $SUBMODULES; do
echo "Delete submodule: $SUBMODULE"
rm -rf "$SUBMODULE"
done
}
function git-submodule-remove() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
echo "Deinit submodule"
git submodule deinit -f "$1"
echo "Move submodule to tmp folder"
mkdir -p tmp/"$1"
mv "$1" tmp/"$1"
echo "Remove submodule from work tree"
git rm -f "$1"
echo "Remove submodule from .git folder"
rm -rf .git/modules/"$1"
}
function git-submodule-init() {
echo "Init git submodules."
# Using "git submodule update --init --recursive" is not possible as modules are registered from different branches
SUBMODULES=$(git-submodule-ls)
for SUBMODULE in $SUBMODULES; do
SHALLOW=$(git config --file .gitmodules --get-regexp submodule."$SUBMODULE".shallow | awk '{ print $2 }')
if [ "$SHALLOW" = "true" ]; then
echo "Initializing submodule: $SUBMODULE (shallow)"
git submodule update --init --depth 1 "$SUBMODULE"
else
echo "Initializing submodule: $SUBMODULE"
git submodule update --init "$SUBMODULE"
fi
done
}
function git-submodule-pull() {
echo "Pull git submodules"
SUBMODULES=$(git-submodule-ls)
for SUBMODULE in $SUBMODULES; do
echo "Pull git submodule: $SUBMODULE"
git -C "$SUBMODULE" stash
UPDATE=$(git config submodule."$SUBMODULE".update)
if [ -z "$UPDATE" ]; then
git -C "$SUBMODULE" pull origin "$GIT_BRANCH"
fi;
done
}
function git-submodule-checkout() {
echo "Checkout submodule commits."
SUBMODULES=$(git-submodule-ls)
for SUBMODULE in $SUBMODULES; do
SHALLOW=$(git config --file .gitmodules --get-regexp submodule."$SUBMODULE".shallow | awk '{ print $2 }')
COMMIT_HASH=$(git ls-tree HEAD "$SUBMODULE" | awk '{print $3}')
if [ "$SHALLOW" = "true" ]; then
echo "Update git submodule: $SUBMODULE (shallow)"
git -C "$SUBMODULE" stash
git -C "$SUBMODULE" fetch origin "$COMMIT_HASH"
git -C "$SUBMODULE" checkout "$COMMIT_HASH"
else
echo "Update git submodule: $SUBMODULE"
git -C "$SUBMODULE" stash
git -C "$SUBMODULE" checkout "$COMMIT_HASH"
fi
done
}
function git-submodule-switch() {
if [ -n "$1" ]; then
GIT_BRANCH="$1"
fi
echo "Switch branch on git submodules."
SUBMODULES=$(git-submodule-ls)
for SUBMODULE in $SUBMODULES; do
echo "Switch git submodule branch to $GIT_BRANCH: $SUBMODULE"
git -C "$SUBMODULE" stash
git -C "$SUBMODULE" switch "$GIT_BRANCH"
done
}
function git-submodule-sync() {
echo "Switch and pull submodules."
git-submodule-switch
git-submodule-pull
}
function git-feature-branch(){
if test -z "$1"; then echo "\$1 is empty."; exit; fi
MODULE_NAME=$(basename "$1")
MODULE_PATH=$(dirname "$1")
echo "Create feature branch for $MODULE_NAME in $MODULE_PATH ..."
cd ./"$MODULE_PATH" || exit
pwd
git switch -c "feature-$MODULE_NAME"
}
function git-mig-branch(){
if test -z "$1"; then echo "\$1 is empty."; exit; fi
MODULE_NAME=$(basename "$1")
MODULE_PATH=$(dirname "$1")
echo "Create mig branch for $MODULE_NAME in $MODULE_PATH ..."
cd ./"$MODULE_PATH" || exit
pwd
git switch -c "$GIT_BRANCH-mig-$MODULE_NAME"
}
function checkout-config-files() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
echo "Checkout config files $1 branch."
git checkout "$1" .git-checkout-files .git-reset-files
echo "Remove reset files."
git rm -r $(tr '\n' ' ' < ./.git-reset-files) >/dev/null 2>&1
echo "Sync checkout files from $1 branch."
git checkout "$1" $(tr '\n' ' ' < ./.git-checkout-files)
}
function checkout() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
GIT_BRANCH="$1"
echo "Switch current branch to $GIT_BRANCH."
git switch "$GIT_BRANCH"
git pull
git-submodule-init
git-submodule-switch
}
# Revision Commands
function list-revision() {
ls scripts/odoo_revision_* | sed 's/scripts\/odoo_revision_//g'
}
function show-revision() {
if [ -n "$1" ]; then
ODOO_REVISION="$1"
fi
ODOO_VERSION=$(echo "$ODOO_REVISION" | cut -d'.' -f1-2)
echo "Load refs for revision: $ODOO_REVISION"
source "scripts/odoo_revision_$ODOO_REVISION"
echo "Odoo Ref: $ODOO_REF"
echo "Odoo Enterprise Ref: $ODOO_ENTERPRISE_REF"
echo "Odoo Themes Ref: $ODOO_THEME_REF"
echo "Odoo Image Ref: $ODOO_IMAGE_REF"
}
function checkout-revision() {
if [ -n "$1" ]; then
ODOO_REVISION="$1"
fi
ODOO_VERSION=$(echo "$ODOO_REVISION" | cut -d'.' -f1-2)
echo "Update revision var in .env file."
if grep -q "ODOO_REVISION" .env; then
sed -i -e "s/^ODOO_REVISION=.*/ODOO_REVISION=${ODOO_REVISION}/" .env
else
echo "ODOO_REVISION=${ODOO_REVISION}" >> .env
fi
echo "Load refs for revision: $ODOO_REVISION"
export $(cat "scripts/odoo_revision_$ODOO_REVISION" | sed 's/#.*//g' | xargs)
echo "Checkout and tag git repos ..."
git -C odoo checkout $ODOO_REF
git -C odoo tag -a $ODOO_REVISION -m "$ODOO_REVISION"
git -C enterprise checkout $ODOO_ENTERPRISE_REF
git -C enterprise tag -a $ODOO_REVISION -m "$ODOO_REVISION"
git -C themes checkout $ODOO_THEME_REF
git -C themes tag -a $ODOO_REVISION -m "$ODOO_REVISION"
if $ODOO_REVISION_CONTAINER_PULL; then
echo "Pull container image ..."
$CONTAINER_ENGINE pull "$ODOO_IMAGE_REF"
IMAGE_ID=$($CONTAINER_ENGINE image inspect "$ODOO_IMAGE_REF" --format "{{ .ID }}")
echo "Tag container image with odoo:$ODOO_REVISION"
$CONTAINER_ENGINE tag "$IMAGE_ID" odoo:$ODOO_REVISION
fi
}
function create-revision() {
if test -z "$1"; then echo "\$1 is empty."; exit; fi
REVISION="$1" # 16.0.20241029
ODOO_VERSION=$(echo "$REVISION" | cut -d'.' -f1-2)
ODOO_DATE=$(echo "$REVISION" | cut -d'.' -f3-)
BEFORE_DATE=$(date -d "$ODOO_DATE -1 day" +"%Y-%m-%d")
# Pull container image with revision
IMAGE=odoo:"$ODOO_VERSION-$ODOO_DATE"
$CONTAINER_ENGINE pull "$IMAGE"
CONTAINER_REF=$($CONTAINER_ENGINE inspect --format='{{index .RepoDigests 0}}' "$IMAGE")
# Get git commit by date
cd odoo
REF=$(git rev-list -n 1 --before="$BEFORE_DATE" origin/$ODOO_VERSION)
git checkout "$REF"
cd ..
cd enterprise
ENTERPRISE_REF=$(git rev-list -n 1 --before="$BEFORE_DATE" origin/$ODOO_VERSION)
git checkout "$ENTERPRISE_REF"
cd ..
cd themes
THEME_REF=$(git rev-list -n 1 --before="$BEFORE_DATE" origin/$ODOO_VERSION)
git checkout "$THEME_REF"
cd ..
echo "Create revision: $REVISION"
export REVISION REF ENTERPRISE_REF THEME_REF CONTAINER_REF
envsubst '$REVISION $REF $ENTERPRISE_REF $THEME_REF $CONTAINER_REF' < templates/odoo_revision > scripts/odoo_revision_"$REVISION"
chmod +x scripts/odoo_revision_"$REVISION"
echo "Checkout revision: $REVISION"
checkout-revision "$REVISION"
}
# RPC Commands
function test-xmlrpc() {
if test -z "$1"; then echo "\$1 is empty."; exit 1; fi
activate-venv
load-env "$1"
echo "Connect to database and count res.partner records: $(scripts/odooctl --model "res.partner" --method "search_count" --domain '[]')"
}
# Pass Commands
function pass-store-dotenv() {
if [ -f .env ]; then
echo "Store .env file in pass: $PASS_ENTRY"
cat .env | pass insert -m -f "$PASS_ENTRY"
else
echo "No .env file found."
fi
}
function pass-restore-dotenv() {
if pass find "$PASS_ENTRY" >/dev/null; then
echo "Restore .env file from pass: $PASS_ENTRY"
pass show "$PASS_ENTRY" > .env
else
echo "Pass entry not found."
fi
}
# LLM Commands
function llm-update() {
if test -z "$1"; then
echo "\$1 is empty.";
exit 1;
fi
# Get list of files
FILES=$(find "$1" -type f \( -name "*.py" -o -name "*.xml" \))
echo -e "Loaded these files into prompt:\n\n$FILES\n"
# Get task description
read -p "Enter the task description: " TASK_DESCRIPTION
# Prepare the files content for prompt
FILE_CONTENTS=""
for file in $FILES; do
FILE_CONTENTS+="<<< $file >>>
$(cat "$file")
"
done
# Define the prompt
PROMPT="EOF
Look at the code files below and do the following:
$TASK_DESCRIPTION
Output your response in the format of a git patch file. The patch should include only the changes to the files, and it should be applicable with 'git apply'. Do not include any explanations or extra information outside of the patch format.
Here are the files:
$FILE_CONTENTS
EOF"
# Run the llm command with the prompt
echo -e "\nWait for the response of the $LLM_MODEL llm."
RESULT=$(llm -m "$LLM_MODEL" "$PROMPT")
# Check if the result is empty
if test -z "$RESULT"; then
echo "No response from the model. Exiting."
exit 1
fi
# Save the patch to a file
PATCH_FILE="tmp/llm_changes.patch"
echo "$RESULT" > "$PATCH_FILE"
echo -e "Saved patch to $PATCH_FILE.\n"
# Preview patch file and ask to apply
git apply --check "$PATCH_FILE"
less "$PATCH_FILE"
read -p "Do you want to apply this patch? (y/n): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
git apply "$PATCH_FILE"
echo "Applied patch file."
fi
}
if declare -f "$1" > /dev/null; then
"$1" "${@:2}"
else
case "$1" in
help)
help task
exit 1
;;
node-install)
npm install
;;
node-dev)
npm run dev
;;
node-build)
npm run build
;;
node-serve-build)
cd .vuepress/dist
npx serve
;;
source)
activate-venv
;;
*)
echo "Unknown command: $1"
help task
exit 1
;;
esac
fi