3250 lines
110 KiB
Bash
Executable File
3250 lines
110 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
|
|
|
|
help-table() {
|
|
local cmd_width=30
|
|
local opt_width=20
|
|
local desc_width=60
|
|
local column="| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n"
|
|
print_separator() {
|
|
echo "|$(printf '%*s' $((cmd_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((opt_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((desc_width + 2)) '' | tr ' ' '-')|"
|
|
}
|
|
print_group_header() {
|
|
local group="$1"
|
|
local group_len=${#group}
|
|
local padding=$((cmd_width - group_len))
|
|
local bold=$(tput bold 2>/dev/null || echo -e "\033[1m")
|
|
local reset=$(tput sgr0 2>/dev/null || echo -e "\033[0m")
|
|
local dashes=$(printf '%*s' $padding '')
|
|
print_separator
|
|
# printf "| %s%s%s%s | %-${opt_width}s | %-${desc_width}s |\n" "$bold" "$group" "$reset" "$dashes" "" ""
|
|
# print_separator
|
|
}
|
|
|
|
printf "$column" 'Command' 'Option' 'Description'
|
|
print_separator
|
|
print_group_header 'Env'
|
|
printf "$column" 'backup-env-files' '[path]' 'Archive and copy ,env files to target location.'
|
|
printf "$column" 'copy-dotenv' '[env][env]' 'Copy .env file.'
|
|
printf "$column" 'create-dotenv' '[env][type]' 'Create .env file of type nextcloud, odoo, upgrade.'
|
|
printf "$column" 'edit-dotenv' '[env]' 'Open .env file in default editor.'
|
|
printf "$column" 'list-dotenv' '' 'List .env files.'
|
|
printf "$column" 'load-dotenv' '' 'Restore content of .env from pass entry.'
|
|
printf "$column" 'load-dotenv' '[env]' 'Load and export .env file.'
|
|
printf "$column" 'remove-dotenv' '[env]' 'Remove environment config.'
|
|
printf "$column" 'rename-dotenv' '[env][env]' 'Rename .env file.'
|
|
printf "$column" 'restore-dotenv-files' '[path]' 'Extract and copy .env files from backup file.'
|
|
printf "$column" 'save-dotenv' '' 'Store content of .env in pass entry.'
|
|
printf "$column" 'show-dotenv' '[env]' 'Output content of the .env file.'
|
|
print_group_header 'Git'
|
|
printf "$column" 'aggregate-git-folders' '[path]' 'Run gitaggregate for the provide repos.yaml.'
|
|
printf "$column" 'add-git-folder' '[url] [path]' 'Add git folder.'
|
|
printf "$column" 'checkout' '[version]' 'Checkout Odoo version.'
|
|
printf "$column" 'checkout-git-folder' '' 'Checkout git commit.'
|
|
printf "$column" 'commit-git-folder' '[message][path]' 'Commit all changes in path.'
|
|
printf "$column" 'clean-git-folder' '' 'Clean git folder.'
|
|
printf "$column" 'clone-git-folder' '[path][version]' 'Clone git folder listed in the .gitmodules file.'
|
|
printf "$column" 'create-git-feature-branch' '[path]' 'Create feature branch for Odoo module.'
|
|
printf "$column" 'create-git-mig-branch' '[path]' 'Create migration branch for Odoo module.'
|
|
printf "$column" 'download-git-folder' '[grep]' 'Download git folder listed in the .gitmodules file.'
|
|
printf "$column" 'status-git-folder' '[path]' 'Show status for git folder in path.'
|
|
printf "$column" 'list-git-folder' '[grep]' 'List path and url of git folders.'
|
|
printf "$column" 'pull-git-folder' '' 'Pull all git folders listed in the .gitmodules file.'
|
|
printf "$column" 'push-git-folder' '' 'Push all git folders in path.'
|
|
printf "$column" 'remove-git-folder' '[path]' 'Remove git folders in path.'
|
|
printf "$column" 'ls-git-folder' '[grep]' 'List git folders path space separated.'
|
|
printf "$column" 'reset-git-folder' '' 'Abort rebase and reset git folder.'
|
|
printf "$column" 'stage-git-folder' '[path]' 'Stage all files in git folders in path.'
|
|
printf "$column" 'switch-git-folder' '[version]' 'Switch branch for all git folders from the .gitmodules file.'
|
|
printf "$column" 'sync-git-folder' '' 'Switch, stash and pull all git folders.'
|
|
print_group_header 'Docker'
|
|
printf "$column" 'archive-docker-tags' '' 'Archive Docker image tags on hub older than 1 year.'
|
|
printf "$column" 'build' '[folder][output]' 'Build Docker image from target folder.'
|
|
printf "$column" 'login-docker' '[user][token]' 'Setup Docker Hub login credentials.'
|
|
printf "$column" 'login-podman' '[user][token]' 'Login into registry with podman.'
|
|
printf "$column" 'container-ps' '' 'List container processes.'
|
|
printf "$column" 'push' '[folder]' 'Publish Docker image from target folder.'
|
|
printf "$column" 'remove' '[name]' 'Remove containers and volumes.'
|
|
printf "$column" 'test-image' '[folder]' 'Test Docker image from target folder.'
|
|
printf "$column" 'test-odoo-version-regex' '' 'Test the Odoo module version regex filter.'
|
|
print_group_header 'Vuepress'
|
|
printf "$column" 'build-vuepress' '' 'Create Vuepress build.'
|
|
printf "$column" 'install-vuepress' '' 'Install Node build dependencies.'
|
|
printf "$column" 'dev-vuepress' '' 'Start Vuepress development server.'
|
|
printf "$column" 'serve-vuepress' '' 'Serve Vuepress build.'
|
|
print_group_header 'Database'
|
|
printf "$column" 'change-uuid' '[env]' 'Change database uuid via xmlrpc.'
|
|
printf "$column" 'clear-assets' '[db]' 'Clear all assets of Odoo database.'
|
|
printf "$column" 'clear-filestore' '[db]' 'Clear local filestore folder.'
|
|
printf "$column" 'clear-views' '[db]' 'Clear all views of Odoo database.'
|
|
printf "$column" 'cloc-odoo' '[db]' 'Count custom line of codes.'
|
|
printf "$column" 'drop-db' '[db]' 'Drop target Odoo database.'
|
|
printf "$column" 'init-db' '[db]' 'Initialize the Odoo database.'
|
|
printf "$column" 'load-language' '[db][lang]' 'Install language package in Odoo db.'
|
|
printf "$column" 'patch-database' '[db][path]' 'Apply sql file to database.'
|
|
printf "$column" 'reset-views' '[db][key]' 'Execute hard reset on views matching keys.'
|
|
printf "$column" 'set-admin' '[db]' 'Sets the password for the first user in database.'
|
|
printf "$column" 'update-module' '[db][name,path]' 'Update target Odoo module.'
|
|
printf "$column" 'update-module-list' '[db]' 'Update module list of Odoo database.'
|
|
print_group_header 'Revision'
|
|
printf "$column" 'checkout-latest-revision' '[version]' 'Checkout the latest revision of the Odoo version.'
|
|
printf "$column" 'checkout-revision' '[revision]' 'Load Odoo revision env var and checkout git folders.'
|
|
printf "$column" 'commit-and-push-revision' '[revision]' 'Commit all changes and tag with current revision.'
|
|
printf "$column" 'create-revision' '[revision]' 'Create new Odoo revision.'
|
|
printf "$column" 'list-revision' '' 'List available Odoo revisions.'
|
|
printf "$column" 'load-latest-revision' '[version]' 'Load the latest revision of the Odoo version.'
|
|
printf "$column" 'load-revision' '[revision]' 'Load env var from specified revision.'
|
|
printf "$column" 'show-revision' '[revision]' 'Show references of Odoo revision.'
|
|
print_group_header 'LLM'
|
|
printf "$column" 'commit-with-llm' '' 'Commit with llm generated commit message.'
|
|
printf "$column" 'show-odoo-mcp-config' '' 'Show the Odoo MCP server config.'
|
|
printf "$column" 'update-with-llm' '[glob][prompt]' 'Feed module files with prompt to LLM and apply file changes.'
|
|
print_group_header 'Snippets'
|
|
printf "$column" 'create-snippet' '[xml-id]' 'Create snippet from template.'
|
|
printf "$column" 'install-snippet' '[env][path]' 'Install snippet definition.'
|
|
printf "$column" 'disable-snippet' '[env][path]' 'Disable snippet by path or xml-id.'
|
|
printf "$column" 'enable-snippet' '[env][path]' 'Enable snippet by path or xml-id.'
|
|
printf "$column" 'lint-snippets' '' 'Run checks for all snippets.'
|
|
printf "$column" 'remove-snippet' '[env][path]' 'Remove snippet by path or xml-id.'
|
|
printf "$column" 'update-snippet' '[env][path]' 'Update snippet definition.'
|
|
print_group_header 'Install'
|
|
printf "$column" 'activate-venv' '' 'Activate virtualenv.'
|
|
printf "$column" 'init-venv' '' 'Initialize python virtual env.'
|
|
printf "$column" 'disable-mailserver' '[env]' 'Disable mail server settings via xmlrpc.'
|
|
printf "$column" 'install' '' 'Install Odoo requirements in source folder.'
|
|
printf "$column" 'install-ansible-build-scripts' '[role]' 'Install scripts of the specified Ansbile role.'
|
|
printf "$column" 'install-requirements' '[db][path]' 'Install python packages from requirements.txt.'
|
|
printf "$column" 'list-packages' '' 'List installed python packages.'
|
|
printf "$column" 'init-module' '[db][path,module]' 'Initialize Odoo module.'
|
|
printf "$column" 'set-addons-path' '' 'Set Odoo addons path env variable.'
|
|
print_group_header 'Migration'
|
|
printf "$column" 'export-website-data' '[env]' 'Export website data from Odoo database.'
|
|
printf "$column" 'import-csv' '[db][path]' 'Import data from csv. Filename is PostgreSQL table name.'
|
|
printf "$column" 'import-website-data' '[env]' 'Import website data to Odoo database.'
|
|
print_group_header 'Generate'
|
|
printf "$column" 'create-module' '[path]' 'Create new Odoo module from template.'
|
|
printf "$column" 'generate-module-docs' '[path]' 'Generate readme file for module with OCA tools.'
|
|
printf "$column" 'generate-module-model' '[path][model]' 'Generate model in module folder.'
|
|
printf "$column" 'generate-module-inherit' '[path][model]' 'Generate inherited model in module folder.'
|
|
printf "$column" 'generate-module-views' '[path][model]' 'Generate model views in module folder.'
|
|
printf "$column" 'generate-module-security' '[path][model]' 'Generate model access file.'
|
|
printf "$column" 'generate-module-migration' '[path]' 'Generate .'
|
|
printf "$column" 'generate-module-snippet' '[path][ref][model]' 'Generate snippet for referefenced view.'
|
|
printf "$column" 'generate-module-wizard' '[path][model]' 'Generate wizard for a model in module folder.'
|
|
printf "$column" 'generate-module-repo' '[path]' 'Initialize Odoo module repo from template.'
|
|
print_group_header 'Module'
|
|
printf "$column" 'list-modules' '[path]' 'Get modules in path as bash array.'
|
|
printf "$column" 'pytest-module' '[path]' 'Run module tests with pytest.'
|
|
printf "$column" 'release-module' '[path]' 'Create GitHub release for a module.'
|
|
printf "$column" 'remove-module' '[db][name]' 'Remove target Odoo module.'
|
|
printf "$column" 'test-module' '[path]' 'Test target Odoo module.'
|
|
printf "$column" 'test-modules' '[path]' 'Test target Odoo modules in repo folder.'
|
|
printf "$column" 'translate-module' '[path][lang][db]' 'Generate translation for Odoo module.'
|
|
printf "$column" 'upload-module' '[env][path]' 'Zip and upload Odoo module.'
|
|
printf "$column" 'visualize-dependencies' '[path]' 'Generate visualizations of module dependencies.'
|
|
printf "$column" 'zip-module' '[path]' 'Create zip file for module.'
|
|
print_group_header 'Helper'
|
|
printf "$column" 'generate-admin-password' '[pass]' 'Generate hash for Odoo master password.'
|
|
printf "$column" 'generate-ssh-keys' '' 'Generate ssh key pair.'
|
|
printf "$column" 'generate-pg-ssl-keys' '' 'Generate PostgreSQL SSL key material.'
|
|
printf "$column" 'get-addons-path' '' 'Output addons path.'
|
|
printf "$column" 'get-modules' '[path][option]' 'Get list of modules in path. '\''basename'\'' or '\''dirname'\''.'
|
|
printf "$column" 'get-module-version' '[path]' 'Get module version from manifest.'
|
|
printf "$column" 'get-module-checksum' '[path]' 'Get module checksum.'
|
|
printf "$column" 'help' '[grep]' 'Show help for commands.'
|
|
printf "$column" 'info' '' 'Show values of project env vars.'
|
|
printf "$column" 'load-ssh-key' '' 'Load SSH private key from env var.'
|
|
printf "$column" 'update-module-license' '[grep]' 'Update LICENSE file for each matching module.'
|
|
print_group_header 'Run'
|
|
printf "$column" 'debug' '[name]' 'Debugg application.'
|
|
printf "$column" 'exec' '[name][cmd]' 'Run command in container.'
|
|
printf "$column" 'logs' '[name]' 'Tail container logs. Default is '\''odoo'\''.'
|
|
printf "$column" 'manifestoo' '[param]' 'Execute manifestoo cli.'
|
|
printf "$column" 'odoocli' '[param]' 'Execute odoocli cli.'
|
|
printf "$column" 'psql' '[db]' 'Start interactive psql shell.'
|
|
printf "$column" 'restart' '[name]' 'Restart container.'
|
|
printf "$column" 'run' '[name][cmd]' 'Run container with command.'
|
|
printf "$column" 'shell' '[db][code]' 'Start interactive odoo shell or run code.'
|
|
printf "$column" 'source' '' 'Source the Python virtual env.'
|
|
printf "$column" 'start' '[name][db]' 'Start service. Use list to show services.'
|
|
printf "$column" 'stop' '[name]' 'Stop containers.'
|
|
printf "$column" 'test-xmlrpc' '[env]' 'Test json rpc connection.'
|
|
print_group_header 'Project'
|
|
printf "$column" 'lint' '' 'Run precommit for this project.'
|
|
printf "$column" 'list-versions' '' 'List available Odoo versions.'
|
|
printf "$column" 'check-version' '' 'Check if Odoo source is the correct version.'
|
|
printf "$column" 'load-version' '[version]' 'Load git refs from version folder.'
|
|
printf "$column" 'save-version' '' 'Save git folder refs to version folder.'
|
|
printf "$column" 'template-compose' '' 'Template the Docker compose file.'
|
|
printf "$column" 'template-odoo-rc' '' 'Template the Odoo config file.'
|
|
printf "$column" 'template-repo' '[path]' 'Update the repo folder from template.'
|
|
printf "$column" 'test-project' '[cleanup]' 'Run tests for this project.'
|
|
printf "$column" 'version' '' 'Show version of required tools.'
|
|
print_group_header 'Performance'
|
|
printf "$column" 'record-with-memray' '[name]' 'Record application memory usage with memray.'
|
|
printf "$column" 'record-with-py-spy' '[pid]' 'Record and create flamechart for a process.'
|
|
print_group_header 'Docs'
|
|
printf "$column" 'update-docs' '' 'Update all project docs.'
|
|
printf "$column" 'update-modules-doc' '' 'Update modules docs file.'
|
|
printf "$column" 'update-revisions-doc' '' 'Update revisions doc file.'
|
|
printf "$column" 'update-snippets-doc' '' 'Update snippets doc file.'
|
|
print_group_header 'Upgrade'
|
|
printf "$column" 'migrate-module' '[path]' 'Migrate module code from to target Odoo version.'
|
|
printf "$column" 'upgrade-odoo' '[env][step]' 'Run the Odoo upgrade for a target environment.'
|
|
}
|
|
|
|
help() {
|
|
echo
|
|
if [[ -n "$1" ]]; then
|
|
help-table | grep -i "$1" | column -t -s'|'
|
|
else
|
|
echo 'task <command> [options]'
|
|
echo
|
|
echo 'commands:'
|
|
echo
|
|
help-table
|
|
fi
|
|
echo
|
|
}
|
|
|
|
|
|
# Static env vars
|
|
|
|
PASS_ENTRY="$(echo "env/${PWD##*/}" | tr '[:upper:]' '[:lower:]')"
|
|
ODOO_RC="odoo.conf"
|
|
TASK_DOTENV_DIR="$PWD/vault"
|
|
export PYTHONPATH="$PWD/odoo" # Required so upgrade-util does not overwrite the odoo namespace
|
|
ODOO_VERSION=$(echo "$ODOO_REVISION" | cut -d'.' -f1-2)
|
|
CONTAINER_CONFIG="$HOME/.docker/$CONTAINER_REGISTRY"
|
|
|
|
# Updateable env vars
|
|
|
|
ORG_NAME=${ORG_NAME:=Mint-System}
|
|
DB_NAME=${DB_NAME:="$ODOO_VERSION"}
|
|
WITHOUT_DEMO=${WITHOUT_DEMO:=False}
|
|
ODOO_LANGUAGE=${ODOO_LANGUAGE:=de_CH}
|
|
ODOO_PORT=${ODOO_PORT:=8069}
|
|
NGINX_PORT=${NGINX_PORT:=8080}
|
|
WORKERS=${WORKERS:=0}
|
|
POSTGRES_IMAGE=${POSTGRES_IMAGE:=postgres:16-alpine}
|
|
POSTGRES_PORT=${POSTGRES_PORT:=5432}
|
|
POSTGRES_SSL=${POSTGRES_SSL:=on}
|
|
PGSSLMODE=${PGSSLMODE:=prefer}
|
|
LOG_LEVEL=${LOG_LEVEL:=info}
|
|
CONTAINER_REGISTRY=${CONTAINER_REGISTRY:=mintsystem}
|
|
PLATFORM=${PLATFORM:=linux/amd64}
|
|
CONTAINER_ENGINE=${CONTAINER_ENGINE:=docker}
|
|
COMPOSE_COMMAND=${COMPOSE_COMMAND:=docker compose}
|
|
LLM_MODEL=${LLM_MODEL:=llama}
|
|
SMTP_SERVER=${SMTP_SERVER:=localhost}
|
|
SMTP_PORT=${SMTP_PORT:=1025}
|
|
SMTP_SSL=${SMTP_SSL:=False}
|
|
EMAIL_FROM=${EMAIL_FROM:=info@yourcompany.com}
|
|
MAIL_ALIAS_DOMAIN=${MAIL_ALIAS_DOMAIN:=yourcompany.com}
|
|
LIST_DB=${LIST_DB:=False}
|
|
CONTAINER_TAG="odoo:$ODOO_REVISION"
|
|
ODOO_INIT_LOGIN=${ODOO_INIT_LOGIN:=admin}
|
|
ODOO_INIT_PASSWORD=${ODOO_INIT_PASSWORD:=admin}
|
|
SNIPPET_PREFIX=${SNIPPET_PREFIX:=mint_system}
|
|
|
|
# Conditional env vars
|
|
|
|
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
|
COMPOSE_COMMAND="podman-compose"
|
|
fi
|
|
|
|
if [[ "$(uname)" == "Darwin" ]]; then
|
|
OS_RELEASE="Darwin"
|
|
PYTHON_NOTIFY=""
|
|
else
|
|
OS_RELEASE=$(awk -F= '/^NAME/{print $2}' /etc/os-release | tr -d '"')
|
|
PYTHON_NOTIFY="inotify"
|
|
fi
|
|
|
|
if [ "$WITHOUT_DEMO" = "True" ]; then
|
|
ODOO_PARAM="--without-demo=all"
|
|
fi
|
|
|
|
# Import commands
|
|
|
|
clone-taskfile(){
|
|
if [[ ! -d "$HOME/taskfile.build" ]]; then
|
|
echo -e '\033[38;5;214mGit\033[0m: Clone taskfile repo'
|
|
git clone https://git.taskfile.build "$HOME/taskfile.build"
|
|
else
|
|
echo -e '\033[38;5;214mGit\033[0m: Pull taskfile repo'
|
|
git -C "$HOME/taskfile.build" pull
|
|
fi
|
|
}
|
|
|
|
if [[ -d "$HOME/taskfile.build/bin" ]]; then
|
|
for file in "$HOME/taskfile.build/bin/"*; do
|
|
if [[ -f "$file" ]]; then
|
|
source "$file"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Help commands
|
|
|
|
info() {
|
|
set-addons-path
|
|
echo "OS Release: $OS_RELEASE"
|
|
echo "Pass Entry: $PASS_ENTRY"
|
|
echo "Odoo Revision: $ODOO_REVISION"
|
|
echo "Odoo Version: $ODOO_VERSION"
|
|
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 "Addons Path: $ADDONS_PATH"
|
|
}
|
|
|
|
version() {
|
|
uv --version
|
|
activate-venv
|
|
python -V
|
|
wkhtmltopdf -V
|
|
if [[ "$CONTAINER_ENGINE" == "docker" ]]; then
|
|
docker -v
|
|
docker compose version
|
|
else
|
|
podman --version
|
|
podman-compose --version
|
|
fi
|
|
}
|
|
|
|
generate-admin-password() {
|
|
if [[ -z "$1" ]]; then echo '\$1 is empty.'; exit; fi
|
|
export ODOO_PASSWORD="$1"
|
|
bin/hash-password
|
|
}
|
|
|
|
show-odoo-mcp-config() {
|
|
echo 'Add this config to your IDE: '
|
|
cat << EOF
|
|
{
|
|
"mcpServers": {
|
|
"odoo": {
|
|
"command": "$PWD/venv$ODOO_VERSION/bin/python",
|
|
"args": ["$PWD/images/odoo-mcp/bin/server"],
|
|
"env": {
|
|
"ODOO_URL": "http://localhost:8069",
|
|
"DB_NAME": "$DB_NAME",
|
|
"ODOO_USERNAME": "admin",
|
|
"ODOO_PASSWORD": "admin"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
}
|
|
|
|
# Env commands
|
|
|
|
init-venv() {
|
|
echo "Ensure Python version $(cat .python-version) is installed."
|
|
uv python install
|
|
|
|
if [[ ! -d ".venv$ODOO_VERSION" ]]; then
|
|
echo "Init .venv$ODOO_VERSION with $(uv --version)."
|
|
uv venv ".venv$ODOO_VERSION"
|
|
fi
|
|
}
|
|
|
|
activate-venv() {
|
|
if [[ -f ".venv$ODOO_VERSION/bin/activate" ]]; then
|
|
source ".venv$ODOO_VERSION/bin/activate"
|
|
else
|
|
echo "Could not find .venv$ODOO_VERSION/bin/active. Use init-venv to initalize."
|
|
fi
|
|
}
|
|
|
|
get-addons-path() {
|
|
set-addons-path
|
|
echo "$ADDONS_PATH"
|
|
}
|
|
|
|
template-odoo-rc() {
|
|
echo "Template $ODOO_RC"
|
|
|
|
# Load and export vars defined in odoo conf template
|
|
for var in $(grep -oE '\$([A-Z_][A-Z0-9_]*)|\$\{([A-Z_][A-Z0-9_]*)\}' odoo.conf.template); do
|
|
var=${var/\$/}
|
|
var=${var//\{\//}
|
|
export $var
|
|
done
|
|
|
|
local ir_config_parameter=${IR_CONFIG_PARAMETER:-""}
|
|
|
|
if [[ -n "$GIT_SSH_PRIVATE_KEY" ]]; then
|
|
local git_ssh_private_key=$(echo -e "$GIT_SSH_PRIVATE_KEY" | base64 -w0)
|
|
ir_config_parameter+=$'\n'"git.ssh_private_key = \"$git_ssh_private_key\""
|
|
fi
|
|
|
|
if [[ -n "$GIT_SSH_PUBLIC_KEY" ]]; then
|
|
ir_config_parameter+=$'\n'"git.ssh_public_key = \"$GIT_SSH_PUBLIC_KEY\""
|
|
fi
|
|
|
|
if [[ -n "$BASE_URL_WEBSITE" ]]; then
|
|
ir_config_parameter+=$'\n'"base_url_website = \"$BASE_URL_WEBSITE\""
|
|
fi
|
|
|
|
if [[ -n "$BASE_URL_APP" ]]; then
|
|
ir_config_parameter+=$'\n'"base_url_app = \"$BASE_URL_APP\""
|
|
fi
|
|
|
|
if [[ -n "$UPLOADCARE_PUBLIC_KEY" ]]; then
|
|
ir_config_parameter+=$'\n'"uploadcare.public_key = \"$UPLOADCARE_PUBLIC_KEY\""
|
|
fi
|
|
|
|
if [[ -n "$UPLOADCARE_SECRET_KEY" ]]; then
|
|
ir_config_parameter+=$'\n'"uploadcare.secret_key = \"$UPLOADCARE_SECRET_KEY\""
|
|
fi
|
|
|
|
if [[ -n "$KEYCLOAK_BASE_URL" ]]; then
|
|
ir_config_parameter+=$'\n'"keycloak.base_url = \"$KEYCLOAK_BASE_URL\""
|
|
fi
|
|
|
|
if [[ -n "$KEYCLOAK_CLIENT_ID" ]]; then
|
|
ir_config_parameter+=$'\n'"keycloak.client_id = \"$KEYCLOAK_CLIENT_ID\""
|
|
fi
|
|
|
|
if [[ -n "$KEYCLOAK_CLIENT_SECRET" ]]; then
|
|
ir_config_parameter+=$'\n'"keycloak.client_secret = \"$KEYCLOAK_CLIENT_SECRET\""
|
|
fi
|
|
|
|
if [[ -n "$KEYCLOAK_REALM" ]]; then
|
|
ir_config_parameter+=$'\n'"keycloak.realm = \"$KEYCLOAK_REALM\""
|
|
fi
|
|
|
|
export IR_CONFIG_PARAMETER="$ir_config_parameter"
|
|
|
|
envsubst < "odoo.conf.template" > "$ODOO_RC"
|
|
}
|
|
|
|
set-addons-path() {
|
|
# Read addons path from git module
|
|
local git_folders_path="$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }' | sort | tr '\n' ',' | sed 's/,*$//')"
|
|
|
|
# Remove excluded addons
|
|
local excludes="addons/theme_mint_system addons/company addons/web"
|
|
for exclude in $excludes; do
|
|
git_folders_path=$(echo "$git_folders_path" | sed "s|${exclude},||g; s|^${exclude}$||")
|
|
done
|
|
|
|
# Filter valid directories
|
|
local valid_paths=""
|
|
while IFS= read -r addon; do
|
|
addon=$(echo "$addon" | xargs)
|
|
[[ -z "$addon" ]] && continue
|
|
if [[ -d "$addon" ]]; then
|
|
valid_paths="${valid_paths:+$valid_paths,}$addon"
|
|
else
|
|
echo "Set Addons Path: Path '$addon' does not exist." >&2
|
|
fi
|
|
done < <(echo "$git_folders_path" | tr ',' '\n')
|
|
git_folders_path="$valid_paths"
|
|
|
|
# Convert to source paths (add /addons where needed)
|
|
local addons_path="$(echo "$git_folders_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
|
|
|
|
# Export the addons path
|
|
export ADDONS_PATH="$addons_path"
|
|
}
|
|
|
|
load-ssh-key() {
|
|
if [[ -n "$GIT_SSH_PRIVATE_KEY" ]]; then
|
|
echo 'Setup SSH key from env var.'
|
|
local decoded_git_ssh_private_key=$(echo -e "$GIT_SSH_PRIVATE_KEY" | base64 -d)
|
|
mkdir -p ~/.ssh
|
|
echo "$decoded_git_ssh_private_key" > ~/.ssh/id_ed25519
|
|
chmod 600 ~/.ssh/id_ed25519
|
|
eval "$(ssh-agent -s)"
|
|
ssh-add ~/.ssh/id_ed25519 || (echo 'Dumping ~/.ssh/id_ed25519 content:' && cat ~/.ssh/id_ed25519)
|
|
else
|
|
echo 'The SSH key env var is empty.'
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Docs commands
|
|
|
|
lint() {
|
|
echo "Run pre-commit in $PWD"
|
|
pre-commit run
|
|
}
|
|
|
|
update-snippets-doc() {
|
|
./bin/update-snippets-doc
|
|
}
|
|
|
|
update-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
|
|
local path_url="https://github.com/${ORG_NAME}/Odoo-Build/tree/main"
|
|
|
|
for file in $(ls revisions/ | sort -rV); do
|
|
local revision="$file"
|
|
local 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 "revisions/$file")
|
|
revisions[$version]+=$'\n```'
|
|
done
|
|
|
|
for revision in $(echo "${!revisions[@]}" | tr ' ' '\n' | sort -rV); do
|
|
echo -e "${revisions[$revision]}\n" >> "revisions.md"
|
|
done
|
|
}
|
|
|
|
update-modules-doc() {
|
|
echo 'Update module doc file.'
|
|
./bin/update-modules-doc
|
|
}
|
|
|
|
update-docs() {
|
|
update-modules-doc
|
|
update-revisions-doc
|
|
update-snippets-doc
|
|
}
|
|
|
|
update-module-license() {
|
|
if [[ -z "$1" ]]; then echo '\$1 is empty.'; exit; fi
|
|
local git_folders=$(list-module "$1")
|
|
|
|
for git_folder in $git_folders; do
|
|
echo "Update license file for $git_folder."
|
|
cp templates/module/LICENSE "$git_folder/"
|
|
done
|
|
}
|
|
|
|
template-repo(){
|
|
if [[ -z "$1" ]]; then echo '\$1 is empty.'; exit; fi
|
|
local repo_path="$1"
|
|
|
|
echo "Copy task file to $repo_path."
|
|
cp "templates/task" "$repo_path"
|
|
|
|
echo "Template README.md to $repo_path."
|
|
export REPO_FOLDER=$(basename "$repo_path")
|
|
export REPO_MODEL=${REPO_FOLDER%%_*}
|
|
export REPO_TITLE=$(echo "$REPO_FOLDER" | sed 's/_/ /g' | sed 's/\b\(.\)/\u\1/g')
|
|
export REPO_NAME=$(echo "$REPO_FOLDER" | sed 's/_/-/g' | sed 's/\b\(.\)/\u\1/g')
|
|
envsubst < "templates/README.md" > "$repo_path/README.md"
|
|
|
|
echo "Copy $ODOO_VERSION template files to $repo_path."
|
|
cp -r "templates/$ODOO_VERSION/." "$repo_path"
|
|
|
|
echo 'Remove deprecated repo files.'
|
|
rm -f "$repo_path/.flake8"
|
|
rm -f "$repo_path/.isort.cfg"
|
|
rm -f "$repo_path/.pylintrc-mandatory"
|
|
}
|
|
|
|
# Module commands
|
|
|
|
get-modules() {
|
|
if [[ -z "$1" ]]; then echo '\$1 is empty.'; exit; fi
|
|
|
|
local option="$2"
|
|
if [[ -z "$option" ]]; then
|
|
option="dirname"
|
|
fi
|
|
|
|
local modules
|
|
if [[ "$option" == "dirname" ]]; then
|
|
modules=$(echo "$1" | tr "," "\n" | xargs -I {} find {} -type f -name "__manifest__.py" | xargs grep -l -iE "version.*([0-9]+\.[0-9]+(\.[0-9]+)?|${ODOO_VERSION}(\.[0-9]+)*)" | 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 -iE "version.*([0-9]+\.[0-9]+(\.[0-9]+)?|${ODOO_VERSION}(\.[0-9]+)*)" | xargs -r dirname | xargs -r -I {} basename {} | sort -u | tr "\n" "," | sed 's/,$//')
|
|
fi
|
|
echo "$modules"
|
|
}
|
|
|
|
get-module-version() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '\$1 is empty.'
|
|
else
|
|
# Get version of module
|
|
local 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
|
|
|
|
local count_dots=$(echo "$version" | grep -o "\." | wc -l)
|
|
|
|
# Check if oca version or enterprise version
|
|
if [[ $count_dots == 2 ]]; then
|
|
version="$ODOO_VERSION.$version"
|
|
fi
|
|
if [[ $count_dots == 1 ]]; then
|
|
version="$ODOO_VERSION.$version"
|
|
fi
|
|
|
|
echo "$version"
|
|
fi
|
|
}
|
|
|
|
get-module-checksum() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '\$1 is empty.'
|
|
else
|
|
bin/get-module-checksum "$1"
|
|
fi
|
|
}
|
|
|
|
list-modules() {
|
|
if [[ -z "$1" ]]; then echo '\$1 is empty.'; exit; fi
|
|
local modules=$(get-modules "$1" dirname)
|
|
echo "$modules" | tr ',' '\n'
|
|
}
|
|
|
|
# Container commands
|
|
|
|
archive-docker-tags() {
|
|
export CONTAINER_CONFIG
|
|
python bin/archive-docker-tags
|
|
}
|
|
|
|
template-compose() {
|
|
echo 'Template compose.yml'
|
|
|
|
# Load and export vars defined in compose template
|
|
for var in $(grep -oE '\$\{?[A-Z_][A-Z0-9_]*\}?' compose.yml.template); do
|
|
# Strip $, ${, }
|
|
var=${var#\$\{} # Remove leading ${
|
|
var=${var%\}} # Remove trailing }
|
|
var=${var#\$} # Remove leading $
|
|
export "$var"
|
|
done
|
|
|
|
# Add volume mounts
|
|
VOLUME_MOUNTS=""
|
|
if [[ -d "./tmp/postgres-odoo" ]]; then
|
|
VOLUME_MOUNTS="${VOLUME_MOUNTS} - ./tmp/postgres-odoo:/mnt/postgres-odoo"$'\n'
|
|
fi
|
|
if [[ -d "./addons" ]]; then
|
|
VOLUME_MOUNTS="${VOLUME_MOUNTS} - ./addons:/mnt/addons"$'\n'
|
|
fi
|
|
if [[ -d "./oca" ]]; then
|
|
VOLUME_MOUNTS="${VOLUME_MOUNTS} - ./oca:/mnt/oca"$'\n'
|
|
fi
|
|
if [[ -d "./enterprise" ]]; then
|
|
VOLUME_MOUNTS="${VOLUME_MOUNTS} - ./enterprise:/mnt/enterprise"$'\n'
|
|
fi
|
|
if [[ -d "./themes" ]]; then
|
|
VOLUME_MOUNTS="${VOLUME_MOUNTS} - ./themes:/mnt/themes"$'\n'
|
|
fi
|
|
VOLUME_MOUNTS="${VOLUME_MOUNTS%$'\n'}"
|
|
export VOLUME_MOUNTS
|
|
|
|
envsubst < "compose.yml.template" > "compose.yml"
|
|
}
|
|
|
|
container-ps() {
|
|
$CONTAINER_ENGINE ps
|
|
}
|
|
|
|
build() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Set container tag based on Dockerfile
|
|
local manifest_file
|
|
local latest_tag
|
|
|
|
if [[ "$1" == "images/odoo" ]]; then
|
|
manifest_file="images/odoo/Dockerfile"
|
|
latest_tag="odoo:$ODOO_VERSION"
|
|
fi
|
|
if [[ "$1" == "images/odoo-mailgate" ]]; then
|
|
manifest_file="images/odoo-mailgate/Dockerfile"
|
|
CONTAINER_TAG="odoo-mailgate"
|
|
latest_tag="odoo-mailgate:latest"
|
|
elif [[ "$1" == "images/odoo-upgrade" ]]; then
|
|
manifest_file="images/odoo-upgrade/Dockerfile"
|
|
CONTAINER_TAG="odoo-upgrade"
|
|
latest_tag="odoo-upgrade:latest"
|
|
elif [[ "$1" == "images/odoocli" ]]; then
|
|
manifest_file="images/odoocli/Dockerfile"
|
|
CONTAINER_TAG="odoocli"
|
|
latest_tag="odoocli:latest"
|
|
elif [[ "$1" == "images/odoo-mcp" ]]; then
|
|
manifest_file="images/odoo-mcp/Dockerfile"
|
|
CONTAINER_TAG="odoo-mcp"
|
|
latest_tag="odoo-mcp:latest"
|
|
fi
|
|
|
|
# Load Odoo revision
|
|
local odoo_date=$(echo "$ODOO_REVISION" | cut -d'.' -f3-)
|
|
source "revisions/$ODOO_REVISION"
|
|
|
|
# Select Python version
|
|
case "$ODOO_VERSION" in
|
|
"15.0")
|
|
local python_version="3.9"
|
|
PLATFORM="linux/amd64"
|
|
;;
|
|
"16.0")
|
|
local python_version="3.11"
|
|
;;
|
|
"17.0")
|
|
local python_version="3.11"
|
|
;;
|
|
"18.0")
|
|
local python_version="3.12"
|
|
;;
|
|
"19.0")
|
|
local python_version="3.13"
|
|
;;
|
|
*)
|
|
local python_version="3.12"
|
|
;;
|
|
esac
|
|
|
|
local docker_output="--load"
|
|
if [[ -n "$2" ]]; then
|
|
docker_output="$2"
|
|
fi
|
|
|
|
# Output configuration
|
|
echo "Python Version: $python_version"
|
|
echo "Platform: $PLATFORM"
|
|
echo "Docker Output: $docker_output"
|
|
|
|
echo "Remove container image with tag ${CONTAINER_REGISTRY}/${CONTAINER_TAG}"
|
|
docker image rm -f "${CONTAINER_REGISTRY}/${CONTAINER_TAG}"
|
|
|
|
if ! docker buildx inspect odoo_builder >/dev/null 2>&1; then
|
|
docker buildx create --name odoo_builder --use
|
|
docker buildx inspect --bootstrap
|
|
else
|
|
docker buildx use odoo_builder
|
|
fi
|
|
|
|
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 PYTHON_VERSION="$python_version" \
|
|
--build-arg ODOO_VERSION="$ODOO_VERSION" \
|
|
--build-arg ODOO_DATE="$odoo_date" \
|
|
--build-arg ODOO_ENTERPRISE_REF="$ODOO_ENTERPRISE_REF" \
|
|
--tag "${CONTAINER_REGISTRY}/${CONTAINER_TAG}" \
|
|
--tag "${CONTAINER_REGISTRY}/${latest_tag}" \
|
|
"$docker_output"
|
|
}
|
|
|
|
load-latest-revision() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_VERSION="$1"
|
|
fi
|
|
|
|
ODOO_REVISION=$(list-revision | grep "$ODOO_VERSION" | tail -n1)
|
|
load-revision "$ODOO_REVISION"
|
|
}
|
|
|
|
checkout-latest-revision() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_VERSION="$1"
|
|
fi
|
|
|
|
ODOO_REVISION=$(list-revision | grep "$ODOO_VERSION" | tail -n1)
|
|
checkout-revision "$ODOO_REVISION"
|
|
check-version
|
|
}
|
|
|
|
container-login() {
|
|
if [[ -n "$1" ]]; then
|
|
CONTAINER_REGISTRY_USERNAME="$1"
|
|
fi
|
|
if [[ -n "$2" ]]; then
|
|
CONTAINER_REGISTRY_PASSWORD="$2"
|
|
fi
|
|
|
|
echo "Docker login with username $CONTAINER_REGISTRY_USERNAME."
|
|
echo "$CONTAINER_REGISTRY_PASSWORD" | docker --config "$CONTAINER_CONFIG" login --username "$CONTAINER_REGISTRY_USERNAME" --password-stdin
|
|
echo "$CONTAINER_REGISTRY_PASSWORD" | docker --config "$CONTAINER_CONFIG" login dhi.io --username "$CONTAINER_REGISTRY_USERNAME" --password-stdin
|
|
}
|
|
|
|
login-podman() {
|
|
if [[ -n "$1" ]]; then
|
|
CONTAINER_REGISTRY_USERNAME="$1"
|
|
fi
|
|
if [[ -n "$2" ]]; then
|
|
CONTAINER_REGISTRY_PASSWORD="$2"
|
|
fi
|
|
|
|
echo "Podman login with username $CONTAINER_REGISTRY_USERNAME."
|
|
podman login --username "$CONTAINER_REGISTRY_USERNAME" --password "$CONTAINER_REGISTRY_PASSWORD" docker.io
|
|
}
|
|
|
|
test-odoo-version-regex() {
|
|
|
|
# If ODOO_VERSION=19.0 then
|
|
# 1.0 Match
|
|
# 1.1 Match
|
|
# 2.5 Match
|
|
# 2.0.0 Match
|
|
# 13.0.1.0.0 No match
|
|
# 14.0.2.1.1 No match
|
|
# 13.0.1.0.0 No match
|
|
# 19.0.0.0.0 Match
|
|
|
|
# Variations of the version key:
|
|
# 'version': '19.0.x',
|
|
# "version": "1.0",
|
|
# 'version': '19.0.1.0.0',
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Find and check versions in module"
|
|
|
|
versions=$(grep -r --include="__manifest__.py" '[\"'\'']version[\"'\'']:.[\"'\'']' addons enterprise oca odoo themes |
|
|
sed -E 's/.+[\"'\'']version[\"'\'']:.[\"'\'']([0-9].+)[\"'\''].+/\1/g' |
|
|
sort -u)
|
|
|
|
ODOO_VERSION="19.0"
|
|
for version in $versions; do
|
|
echo -n "Check version $version: "
|
|
# 1. regex: version.[0-9]\.[0-9]$
|
|
# 2. regex: version.[0-9]\.[0-9]\.[0-9]$
|
|
# 3. regex: version.${ODOO_VERSION}\.[0-9]\.[0-9]\.[0-9]$
|
|
if [[ $version =~ ^[0-9]+\.[0-9]+$ ||
|
|
$version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ||
|
|
$version =~ ^${ODOO_VERSION}\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
echo "✓ Match"
|
|
else
|
|
echo "✗ No match"
|
|
fi
|
|
done
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Run set-addons-path"
|
|
export PATH=./images/odoo/bin/:$PATH
|
|
export TEST_ADDONS_DIR="./templates,./themes,./enterprise,/gugus,./oca,./addons"
|
|
export ODOO_VERSION="19.0"
|
|
source ./images/odoo/bin/set-addons-path
|
|
echo "ADDONS_PATH: $ADDONS_PATH"
|
|
}
|
|
|
|
test-image() {
|
|
# Test the scripts of the Docker images without starting the enviroment.
|
|
set -e
|
|
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
if [[ "$1" == "images/odoo-upgrade" ]]; then
|
|
CONTAINER_TAG="odoo-upgrade"
|
|
elif [[ "$1" == "images/odoocli" ]]; then
|
|
CONTAINER_TAG="odoocli"
|
|
fi
|
|
|
|
if [[ "$CONTAINER_TAG" =~ ^odoo: ]]; then
|
|
generate-ssh-keys
|
|
export GIT_SSH_PRIVATE_KEY
|
|
export GIT_SSH_PUBLIC_KEY
|
|
export PATH=./images/odoo/bin/:$PATH
|
|
export LOCAL_PATH="./tmp"
|
|
mkdir -p "$LOCAL_PATH"
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Run git clone addons"
|
|
local server_tools_git_ref=$(curl -s "https://api.github.com/repos/OCA/server-tools/branches/$ODOO_VERSION" | grep '"sha":' | head -n 1 | awk -F '"' '{print $4}')
|
|
export ADDONS_GIT_REPOS="https://github.com/OCA/server-tools.git#${ODOO_VERSION}#${server_tools_git_ref}"
|
|
# This will remove all SSH keys at the end
|
|
./images/odoo/bin/clone-git-addons
|
|
rm -rf "$LOCAL_PATH/github.com" # Cleanup for next run
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Install python package."
|
|
export PYTHON_INSTALL="prometheus-client,pyjwt"
|
|
./images/odoo/bin/install-python-packages
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Sync python project."
|
|
cat > tmp/pyproject.toml << 'EOF'
|
|
[project]
|
|
name = "test-project"
|
|
version = "0.1.0"
|
|
description = "Test project for uv sync"
|
|
dependencies = [
|
|
"requests>=2.28.0",
|
|
"click>=8.0.0",
|
|
]
|
|
|
|
[build-system]
|
|
requires = ["setuptools>=61.0", "wheel"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[tool.uv]
|
|
dev-dependencies = [
|
|
"pytest>=7.0.0",
|
|
"black>=23.0.0",
|
|
]
|
|
EOF
|
|
./images/odoo/bin/sync-python-project
|
|
uv pip list
|
|
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Parse url."
|
|
git_proto=$(./images/odoo/bin/parse-url "git@github.com:OCA/server-tools.git" proto)
|
|
[[ "$git_proto" == "ssh://" ]] && log-success "Test success."
|
|
fi
|
|
|
|
if [[ "$CONTAINER_TAG" =~ ^odoo-upgrade ]]; then
|
|
echo -e "\033[38;5;214mTEST\033[0m: Show help of odoo-upgrade."
|
|
docker run -it mintsystem/odoo-upgrade --help
|
|
fi
|
|
|
|
if [[ "$CONTAINER_TAG" =~ ^odoocli ]]; then
|
|
echo -e "\033[38;5;214mTEST\033[0m: Show help of odoocli."
|
|
docker_odoocli() {
|
|
docker run -it \
|
|
-e ODOO_URL="$ODOO_URL" -e DB_NAME="$DB_NAME" -e ODOO_USERNAME="$ODOO_USERNAME" -e ODOO_PASSWORD="$ODOO_PASSWORD" \
|
|
mintsystem/odoocli "$@"
|
|
}
|
|
docker_odoocli --help
|
|
fi
|
|
}
|
|
|
|
push() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local latest_tag
|
|
|
|
if [[ "$1" == "images/odoo" ]]; then
|
|
latest_tag="odoo:$ODOO_VERSION"
|
|
elif [[ "$1" == "images/odoo-mailgate" ]]; then
|
|
CONTAINER_TAG="odoo-mailgate"
|
|
latest_tag="odoo-mailgate:latest"
|
|
elif [[ "$1" == "images/odoo-upgrade" ]]; then
|
|
CONTAINER_TAG="odoo-upgrade"
|
|
latest_tag="odoo-upgrade:latest"
|
|
elif [[ "$1" == "images/odoocli" ]]; then
|
|
CONTAINER_TAG="odoocli"
|
|
latest_tag="odoocli:latest"
|
|
elif [[ "$1" == "images/odoo-mcp" ]]; then
|
|
CONTAINER_TAG="odoo-mcp"
|
|
latest_tag="odoocli:latest"
|
|
fi
|
|
|
|
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
|
|
|
|
if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
|
|
echo "Push container image to ${CONTAINER_REGISTRY}/${CONTAINER_TAG}"
|
|
podman push "${CONTAINER_REGISTRY}/${CONTAINER_TAG}"
|
|
podman push "${CONTAINER_REGISTRY}/${latest_tag}"
|
|
fi
|
|
}
|
|
|
|
upload-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Check if path is root folder
|
|
local 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
|
|
local version=$(get-module-version "$module")
|
|
local module_name=$(basename "$module")
|
|
local file_path="tmp/$module_name-$version.zip"
|
|
load-dotenv "$1"
|
|
local 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_name\n"
|
|
UPLOADS+=" version: $version\n"
|
|
fi
|
|
done
|
|
|
|
echo 'odoo_apps:'
|
|
echo -e "$UPLOADS"
|
|
}
|
|
|
|
logs() {
|
|
local container="$1"
|
|
container=${container:="odoo"}
|
|
$CONTAINER_ENGINE logs --follow "$container"
|
|
}
|
|
|
|
# Install commands
|
|
|
|
install() {
|
|
init-venv
|
|
activate-venv
|
|
|
|
if [[ ! -d "$HOME/taskfile.build" ]]; then
|
|
echo -e '\033[38;5;214mGit\033[0m: Clone taskfile repo'
|
|
git clone https://git.taskfile.build "$HOME/taskfile.build"
|
|
else
|
|
echo -e '\033[38;5;214mGit\033[0m: Pull taskfile repo'
|
|
git -C "$HOME/taskfile.build" pull
|
|
fi
|
|
|
|
# OS specific installations
|
|
if [[ "$OS_RELEASE" =~ ^(Debian|Debian GNU/Linux|Ubuntu|Pop!_OS)$ ]]; then
|
|
|
|
echo -e "\033[38;5;214mApt\033[0m: Update apt repo"
|
|
sudo apt update
|
|
|
|
echo -e "\033[38;5;214mApt\033[0m: Install python-ldap and psycopg2 build dependencies"
|
|
sudo apt-get install -y libsasl2-dev libldap2-dev libssl-dev libpq-dev python3-dev
|
|
|
|
echo -e "\033[38;5;214mApt\033[0m: Install xmllint, ripgrep and gettext"
|
|
sudo apt install -y libxml2-utils ripgrep gettext
|
|
|
|
elif [[ "$OS_RELEASE" =~ ^(Fedora Linux)$ ]]; then
|
|
|
|
echo -e "\033[38;5;214mDnf\033[0m: Update dnf repo"
|
|
sudo dnf update
|
|
|
|
echo -e "\033[38;5;214mDnf\033[0m: Install psycopg2 build dependencies"
|
|
sudo dnf install -y postgresql-devel
|
|
|
|
echo -e "\033[38;5;214mApt\033[0m: Install ripgrep and gettext"
|
|
sudo dnf install -y ripgrep gettext
|
|
|
|
elif [[ "$OS_RELEASE" =~ ^(Darwin)$ ]]; then
|
|
|
|
echo 'Welcome daring Mac user. Let'\''s try our best to get this working.'
|
|
echo -e "\033[38;5;214mBrew\033[0m: Install required packages with brew."
|
|
brew install gettext libsasl2 openldap openssl libxml2 grep ripgrep
|
|
|
|
elif [[ "$OS_RELEASE" =~ ^(Arch Linux|SteamOS)$ ]]; then
|
|
|
|
echo 'Arch is the best'
|
|
|
|
echo -e "\033[38;5;214mPacman\033[0m: Install python-ldap and psycopg2 build dependencies"
|
|
sudo pacman -S --noconfirm base-devel postgresql-devel
|
|
|
|
echo -e "\033[38;5;214mApt\033[0m: Install ripgrep"
|
|
sudo pacman -S --noconfirm ripgrep
|
|
|
|
else
|
|
echo "The operating system $OS_RELEASE is not supported."
|
|
exit 1
|
|
fi
|
|
|
|
# Install wkhtmltopdf
|
|
if [[ "$OS_RELEASE" =~ ^(Arch Linux|Darwin|Debian|Debian GNU/Linux|Fedora Linux|Ubuntu|Pop!_OS|SteamOS)$ ]]; then
|
|
|
|
# Source: https://gist.github.com/faniska/37f896d5e9de5fee925925d7caf3cb9e
|
|
local installed_version=$(wkhtmltopdf --version 2>&1 | sed -E 's/^wkhtmltopdf +([0-9.]+).*/\1/')
|
|
if [[ "$installed_version" != "0.12.4" ]]; then
|
|
echo -e "\033[38;5;214mCurl\033[0m: Install wkhtmltopdf"
|
|
curl -L -O https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
|
|
tar xvf wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
|
|
sudo mv wkhtmltox/bin/wkhtmlto* /usr/bin/
|
|
rm -rf wkhtmltox wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
|
|
else
|
|
echo 'wkhtmltopdf version is already 0.12.4'
|
|
fi
|
|
fi
|
|
|
|
# Odoo Build requirements
|
|
echo -e "\033[38;5;214mPython\033[0m: Install Odoo Build development tools"
|
|
uv pip install -r requirements.txt
|
|
|
|
# Odoo requirements
|
|
echo -e "\033[38;5;214mPython\033[0m: Install Odoo and dependencies."
|
|
cd odoo
|
|
uv pip install -e .
|
|
grep -v "python-ldap" requirements.txt | uv pip install -r -
|
|
cd ..
|
|
|
|
# Install inotify
|
|
echo -e "\033[38;5;214mPython\033[0m: Install $PYTHON_NOTIFY."
|
|
if [[ -n "$PYTHON_NOTIFY" ]]; then
|
|
uv pip install "$PYTHON_NOTIFY"
|
|
fi
|
|
if [[ "$PYTHON_NOTIFY" == "inotify" ]] && ! sudo grep -q "fs.inotify.max_user_watches=524288" /etc/sysctl.d/99-sysctl.conf; then
|
|
sudo bash -c 'echo "fs.inotify.max_user_watches=524288" >> /etc/sysctl.d/99-sysctl.conf'
|
|
sudo sysctl -p /etc/sysctl.d/99-sysctl.conf
|
|
echo -e "\033[38;5;214mSystem\033[0m: Updated fs.inotify.max_user_watches to 524288"
|
|
fi
|
|
|
|
# Fixes for Odoo versions
|
|
if [[ "$ODOO_VERSION" == "14.0" ]] ; then
|
|
echo -e "\033[38;5;214mPython\033[0m: Fix shebang for odoo binary."
|
|
sed -i '1s|.*|#!'"$PWD"'/.venv14.0/bin/python|' .venv14.0/bin/odoo
|
|
fi
|
|
|
|
}
|
|
|
|
# Process commands
|
|
|
|
start() {
|
|
set-addons-path
|
|
if [[ "$POSTGRES_SSL" == "on" ]]; then
|
|
generate-pg-ssl-keys
|
|
fi
|
|
ODOO_COMMAND="odoo --dev=all"
|
|
if [[ "$1" =~ "odoo-nginx" ]]; then
|
|
ODOO_COMMAND="odoo-nginx --dev=all"
|
|
fi
|
|
export ODOO_COMMAND
|
|
if [[ "$1" =~ "odoo" && -a ".env.odoo" ]]; then
|
|
source .env.odoo
|
|
fi
|
|
|
|
template-compose
|
|
|
|
# Use default database if second param is not given
|
|
local database="$2"
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
|
|
if [[ -z "$1" ]]; then
|
|
echo "Start all container ${CONTAINER_REGISTRY}/${CONTAINER_TAG}"
|
|
echo 'Open http://localhost:8069 url in your browser.'
|
|
$COMPOSE_COMMAND up -d
|
|
fi
|
|
|
|
if [[ "$1" = "list" ]]; then
|
|
echo "Options:"
|
|
echo "admin"
|
|
echo "db"
|
|
echo "mailgate"
|
|
echo "mailpit"
|
|
echo "source"
|
|
echo "hatch"
|
|
echo "odoo"
|
|
echo "odoo-nginx"
|
|
fi
|
|
|
|
if [[ "$1" =~ "admin" ]]; then
|
|
echo 'Open http://localhost:8000 url in your browser.'
|
|
open-url-with-delay "http://localhost:8000" 2 & $COMPOSE_COMMAND up -d admin
|
|
fi
|
|
|
|
if [[ "$1" =~ "db" ]]; then
|
|
$COMPOSE_COMMAND up -d db
|
|
fi
|
|
|
|
if [[ "$1" =~ "mailgate" ]]; then
|
|
echo 'Send emails to: smtp://localhost:587'
|
|
$COMPOSE_COMMAND up -d mailgate
|
|
fi
|
|
|
|
if [[ "$1" =~ "mailpit" ]]; then
|
|
echo 'Open http://localhost:8025 url in your browser.'
|
|
open-url-with-delay "http://localhost:8025" 2 & $COMPOSE_COMMAND up -d mailpit
|
|
fi
|
|
|
|
if [[ "$1" =~ "source" ]]; then
|
|
template-odoo-rc
|
|
local port=8069
|
|
while [[ $port -le 8079 ]]; do
|
|
if ! lsof -i:$port >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
port=$((port + 1))
|
|
done
|
|
|
|
echo "Open http://localhost:$port url in your browser."
|
|
open-url-with-delay "http://localhost:$port/web?debug=1&db=$database" 2 &
|
|
odoo --database="$database" --config "$ODOO_RC" \
|
|
--http-port="$port" --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL"
|
|
fi
|
|
|
|
if [[ "$1" =~ "hatch" ]]; then
|
|
template-odoo-rc
|
|
local port=8069
|
|
while [[ $port -le 8079 ]]; do
|
|
if ! lsof -i:$port >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
port=$((port + 1))
|
|
done
|
|
|
|
echo "Open http://localhost:$port url in your browser."
|
|
open-url-with-delay "http://localhost:$port/web?debug=1&db=$database" 2 &
|
|
odoo --database="$database" --config "$ODOO_RC" \
|
|
--http-port="$port" --dev=all --log-level="$LOG_LEVEL"
|
|
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" 2 & $COMPOSE_COMMAND up -d odoo
|
|
fi
|
|
|
|
if [[ "$1" =~ "odoo-nginx" ]]; then
|
|
echo "Start Odoo container ${CONTAINER_REGISTRY}/${CONTAINER_TAG} with nginx proxy."
|
|
echo 'Open http://localhost:8080 url in your browser.'
|
|
open-url-with-delay "http://localhost:8080" 2 & $COMPOSE_COMMAND up -d odoo
|
|
fi
|
|
}
|
|
|
|
debug() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
set-addons-path
|
|
|
|
local port=8069
|
|
|
|
if [[ "$1" =~ "source" ]]; then
|
|
# Disable file validation to avoid frozen modules warning
|
|
export PYDEVD_DISABLE_FILE_VALIDATION=1
|
|
|
|
echo 'Starting Odoo with the debugger on port 5678.'
|
|
echo "Attach a debugpy debugger and open http://localhost:$port url in your browser."
|
|
|
|
python -m debugpy --listen 5678 --wait-for-client $(which odoo) --database="$DATABASE" --config "$ODOO_RC" \
|
|
--http-port="$port" --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL"
|
|
fi
|
|
}
|
|
|
|
run() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
template-compose
|
|
|
|
echo "Run '$1' container with command '$2'."
|
|
$COMPOSE_COMMAND run --rm "$1" "$2" "$3"
|
|
}
|
|
|
|
exec() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local container="$1"
|
|
shift
|
|
local cmd="$@"
|
|
|
|
echo "Execute command '$cmd' with $CONTAINER_EXEC_PARAM in container '$container'."
|
|
$CONTAINER_ENGINE exec $CONTAINER_EXEC_PARAM "$container" $cmd
|
|
}
|
|
|
|
record-with-py-spy() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local pid="$1"
|
|
local output_file="tmp/speedscope-capture.json"
|
|
local speedscope_url="https://www.speedscope.app/"
|
|
|
|
mkdir -p tmp
|
|
echo "source task source; py-spy record --pid $pid --output $output_file --format speedscope" | sudo bash --
|
|
|
|
open-with-os "$speedscope_url"
|
|
}
|
|
|
|
record-with-memray() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
set-addons-path
|
|
|
|
local port=8069
|
|
local output_file="tmp/memray-capture.bin"
|
|
|
|
if [[ "$1" =~ "source" ]]; then
|
|
|
|
echo 'Starting Odoo with memray.'
|
|
echo "Open http://localhost:$port url in your browser."
|
|
|
|
mkdir -p tmp
|
|
rm "$output_file"
|
|
python3 -m memray run -o "$output_file" $(which odoo) --database="$DATABASE" --config "$ODOO_RC" \
|
|
--http-port="$port" --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL"
|
|
python3 -m memray flamegraph "$output_file"
|
|
open-with-os "tmp/memray-flamegraph-output.html"
|
|
fi
|
|
}
|
|
|
|
remove() {
|
|
template-compose
|
|
|
|
if [[ -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" =~ "mailpit" ]]; then
|
|
$COMPOSE_COMMAND rm -f -s -v mail
|
|
fi
|
|
|
|
if [[ "$1" =~ "mailgate" ]]; then
|
|
$COMPOSE_COMMAND rm -f -s -v mailgate
|
|
fi
|
|
}
|
|
|
|
restart() {
|
|
template-compose
|
|
|
|
if [[ -z "$1" ]]; then
|
|
$COMPOSE_COMMAND restart
|
|
fi
|
|
|
|
if [[ "db|mail|odoo" =~ $1 ]]; then
|
|
$COMPOSE_COMMAND restart "$1"
|
|
fi
|
|
}
|
|
|
|
stop() {
|
|
template-compose
|
|
|
|
if [[ -z "$1" ]]; then
|
|
$COMPOSE_COMMAND stop
|
|
fi
|
|
|
|
$COMPOSE_COMMAND stop "$1"
|
|
}
|
|
|
|
generate-ssh-keys() {
|
|
if [[ -z "$GIT_SSH_PRIVATE_KEY" ]]; then
|
|
echo 'Generate SSH private and public keys.'
|
|
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
|
|
}
|
|
|
|
generate-pg-ssl-keys() {
|
|
local keymaterial_path="tmp/postgres-odoo"
|
|
local postgres_uid=70
|
|
local postgres_gid=70
|
|
|
|
if [[ "$POSTGRES_IMAGE" == "pgvector/pgvector"* ]]; then
|
|
postgres_uid=999
|
|
postgres_gid=999
|
|
fi
|
|
|
|
if [[ -z "$PG_SSL_CA_CRT" ]] || [[ -z "$PG_SSL_SERVER_CRT" ]] || [[ -z "$PG_SSL_SERVER_KEY" ]]; then
|
|
echo 'Generate PostgreSQL SSL/TLS certificates.'
|
|
mkdir -p "$keymaterial_path"
|
|
|
|
if [[ ! -f "$keymaterial_path/ca.crt" ]]; then
|
|
openssl genrsa -out "$keymaterial_path/ca.key" 4096
|
|
chmod 600 "$keymaterial_path/ca.key"
|
|
openssl req -x509 -new -nodes -key "$keymaterial_path/ca.key" -sha256 -days 3650 \
|
|
-out "$keymaterial_path/ca.crt" -subj "/C=CH/ST=State/L=Locality/O=Organization/CN=Root CA"
|
|
fi
|
|
|
|
if [[ ! -f "$keymaterial_path/server.crt" ]]; then
|
|
openssl genrsa -out "$keymaterial_path/server.key" 2048
|
|
openssl req -new -key "$keymaterial_path/server.key" -out "$keymaterial_path/server.csr" \
|
|
-subj "/C=CH/ST=State/L=Locality/O=Organization/CN=localhost"
|
|
openssl x509 -req -in "$keymaterial_path/server.csr" -CA "$keymaterial_path/ca.crt" \
|
|
-CAkey "$keymaterial_path/ca.key" -CAcreateserial -out "$keymaterial_path/server.crt" \
|
|
-days 365 -sha256
|
|
fi
|
|
|
|
local current_uid=$(stat -c '%u' "$keymaterial_path/server.key" 2>/dev/null || stat -f '%u' "$keymaterial_path/server.key" 2>/dev/null)
|
|
|
|
if [[ "$current_uid" != "$postgres_uid" ]]; then
|
|
chmod 600 "$keymaterial_path/server.key"
|
|
chmod 644 "$keymaterial_path/server.crt"
|
|
chmod 644 "$keymaterial_path/ca.crt"
|
|
sudo chown "$postgres_uid:$postgres_gid" "$keymaterial_path/server.key" "$keymaterial_path/server.crt" "$keymaterial_path/ca.crt"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
test-project() {
|
|
# This starts the Docker environment and uses internal and external tools to run commands.
|
|
|
|
if [[ "$1" == "cleanup" ]]; then
|
|
echo -e "\033[38;5;214mTEST\033[0m: Cleanup test environment."
|
|
drop-db test
|
|
remove odoo
|
|
git -C oca/partner-contact clean -df
|
|
git -C oca/partner-contact checkout .
|
|
remove-dotenv test
|
|
else
|
|
version
|
|
info
|
|
set -e
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Clone module repo with https"
|
|
(git clone -b "$ODOO_VERSION" https://github.com/OCA/partner-contact.git oca/partner-contact) || true
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Start container environment."
|
|
export BROWSER_OPEN=false
|
|
start db,mail
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Clone Odoo addons."
|
|
generate-ssh-keys
|
|
export GIT_SSH_PRIVATE_KEY
|
|
export GIT_SSH_PUBLIC_KEY
|
|
export ADDONS_GIT_REPOS="https://github.com/OCA/server-env.git#${ODOO_VERSION},https://github.com/OCA/server-tools.git#${ODOO_VERSION},https://github.com/Mint-System/Odoo-Apps-Server-Tools.git#${ODOO_VERSION}"
|
|
run odoo clone-git-addons
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Init Odoo database."
|
|
export ODOO_ADDONS_PATH="/mnt/oca/partner-contact"
|
|
export DB_NAME=test
|
|
export WITHOUT_DEMO=False
|
|
export ODOO_INIT_LOGIN=test
|
|
export ODOO_INIT_PASSWORD=test
|
|
export ODOO_INIT_LANG=de_CH
|
|
export ODOO_INIT_ADDONS=server_environment_ir_config_parameter,module_auto_update,prometheus_exporter,mail_server_filter,contacts,web_enterprise
|
|
export PYTHON_INSTALL=prometheus-client,manifestoo
|
|
run odoo init-db
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Start Odoo container."
|
|
export ODOO_MAIL_SMTP_HOST=mail
|
|
export ODOO_MAIL_SMTP_PORT=1025
|
|
export ODOO_MAIL_SMTP_ENCRYPTION=none
|
|
export SERVER_WIDE_MODULES=module_change_auto_install
|
|
export MODULE_AUTO_INSTALL_DISABLED=odoo_test_xmlrunner
|
|
export AUTO_UPDATE_TRANSLATIONS=True
|
|
export AUTO_UPDATE_MODULES_LIST=True
|
|
export MAIL_DEFAULT_FROM="test"
|
|
export BROWSER_OPEN=false
|
|
export TEST_ADDONS_DIR=/mnt/oca/partner-contact
|
|
export TEST_INCLUDE=partner_firstname
|
|
start odoo
|
|
TIMEOUT=60
|
|
ELAPSED=0
|
|
until curl --silent --fail "http://localhost:8069/web/login" &> /dev/null; do
|
|
if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
|
|
echo "Odoo did not start within $TIMEOUT seconds."
|
|
docker logs odoo
|
|
exit 1
|
|
fi
|
|
echo 'Waiting for Odoo to be ready...'
|
|
sleep 3
|
|
ELAPSED=$((ELAPSED + 3))
|
|
done
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Init repos.yml file."
|
|
cat << EOF > tmp/repos.yml
|
|
github.com/Mint-System/Odoo-Apps-Partner-Contact:
|
|
remotes:
|
|
mint_system: https://github.com/Mint-System/Odoo-Apps-Partner-Contact.git
|
|
merges:
|
|
- mint_system ${ODOO_VERSION}
|
|
target: mint_system ${ODOO_VERSION}
|
|
EOF
|
|
docker cp tmp/repos.yml odoo:/var/lib/odoo/git/repos.yml
|
|
exec odoo aggregate-git-repos
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Init OCA module."
|
|
exec odoo init-module partner_firstname
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Setup and check RPC credentials."
|
|
export ODOO_URL="http://localhost:8069"
|
|
export ODOO_DATABASE=test
|
|
export ODOO_USERNAME=test
|
|
export ODOO_PASSWORD=test
|
|
if ! show-dotenv test; then
|
|
create-dotenv test odoo
|
|
fi
|
|
show-dotenv test
|
|
test-xmlrpc test
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Install, update, disable and remove snippet."
|
|
install-snippet test snippets/mint_system.base.view_partner_form.show_type.xml
|
|
update-snippet test snippets/mint_system.base.view_partner_form.show_type.xml
|
|
disable-snippet test snippets/mint_system.base.view_partner_form.show_type.xml
|
|
remove-snippet test snippets/mint_system.base.view_partner_form.show_type.xml
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Check module auto update."
|
|
sed -i 's/First name/Firstname/g' oca/partner-contact/partner_firstname/models/res_partner.py
|
|
exec odoo update-modules
|
|
#FIXME: Check if module is auto updated
|
|
# docker logs odoo 2>&1 | grep "Run click-odoo-update."
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Check translations auto update."
|
|
sed -i 's/Nachname/Familienname/g' oca/partner-contact/partner_firstname/i18n/de.po
|
|
restart odoo
|
|
#FIXME: Check if translations updated
|
|
# docker logs odoo 2>&1 | grep "Updating translations for all active languages and installed modules."
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Drop the test database."
|
|
drop-db test
|
|
|
|
#FIXME: These tests do not work in GitHub Runner env.
|
|
# echo -e "\033[38;5;214mTEST\033[0m: Prepare container for testing."
|
|
# exec odoo setup-tests
|
|
# exec odoo ls /var/lib/odoo/git/github.com/Mint-System/Odoo-Apps-Partner-Contact
|
|
|
|
# echo -e "\033[38;5;214mTEST\033[0m: Run module tests."
|
|
# CONTAINER_EXEC_PARAM="-w /mnt/oca/partner-contact"
|
|
# exec odoo run-tests
|
|
|
|
echo -e "\033[38;5;214mTEST\033[0m: Run module migration."
|
|
echo "Setup pre migration script for partner_firstname..."
|
|
mkdir -p oca/partner-contact/partner_firstname/migrations/${ODOO_VERSION}.2.0.0
|
|
cat << EOF > oca/partner-contact/partner_firstname/migrations/${ODOO_VERSION}.2.0.0/pre-migrate.py
|
|
import logging
|
|
from odoo.upgrade import util
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def migrate(cr, version):
|
|
env = util.env(cr)
|
|
|
|
partners = env["res.partner"].search([])
|
|
for partner in partners:
|
|
partner.name += "!"
|
|
|
|
_logger.info("Updated %s partners", len(partners))
|
|
EOF
|
|
sed -i "/\"version\":/c\ \"version\": \"${ODOO_VERSION}.2.0.0\"," oca/partner-contact/partner_firstname/__manifest__.py
|
|
echo "Execute the module upgrade."
|
|
exec odoo update-module partner_firstname
|
|
#FIXME: Check if module is migrated
|
|
# docker logs odoo 2>&1 | grep "module partner_firstname: Running migration"
|
|
fi
|
|
}
|
|
|
|
# Interactive Shell commands
|
|
|
|
shell() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
local code="$2"
|
|
|
|
set-addons-path
|
|
if [[ -n "$code" ]]; then
|
|
echo "$code" | odoo shell --database "$database" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
|
|
else
|
|
odoo shell --database "$database" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
|
|
fi
|
|
}
|
|
|
|
psql() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
|
|
$CONTAINER_ENGINE exec -it db psql "postgres://odoo:odoo@localhost:5432/$database"
|
|
}
|
|
|
|
# Database commands
|
|
|
|
init-db() {
|
|
local odoo_init_addons="${ODOO_INIT_ADDONS:-"web"}"
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
|
|
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
|
|
}
|
|
|
|
import-csv() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local file_path="$2"
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
file_path="$1"
|
|
fi
|
|
|
|
local 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;"
|
|
}
|
|
|
|
drop-db() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
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\";"
|
|
}
|
|
|
|
load-language() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local language="$2"
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
language="$1"
|
|
fi
|
|
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"
|
|
}
|
|
|
|
set-admin() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
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;"
|
|
}
|
|
|
|
clear-assets() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
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_%';"
|
|
}
|
|
|
|
clear-views() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
|
|
echo "Archive views with prefix '$SNIPPET_PREFIX."
|
|
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$database" -c "SELECT id,name from ir_ui_view WHERE name like '%$SNIPPET_PREFIX%';"
|
|
$CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$database" -c "UPDATE ir_ui_view SET active=false WHERE name like '%$SNIPPET_PREFIX%';"
|
|
|
|
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);"
|
|
}
|
|
|
|
clear-filestore() {
|
|
echo "Remove directory $HOME/.local/share/Odoo/filestore/$1"
|
|
rm -rf "$HOME/.local/share/Odoo/filestore/$1"
|
|
}
|
|
|
|
disable-mailserver() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
load-dotenv "$1"
|
|
images/odoocli/bin/odoocli --method 'write' --model 'ir.mail_server' --field 'active' --value False --domain "[]"
|
|
images/odoocli/bin/odoocli --method 'write' --model 'fetchmail.server' --field 'active' --value False --domain "[]"
|
|
}
|
|
|
|
change-uuid() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
load-dotenv "$1"
|
|
local uuid=$(uuidgen)
|
|
echo "Set uuid $uuid for $1."
|
|
images/odoocli/bin/odoocli --method 'write' --model 'ir.config_parameter' --domain "[('key', '=', 'database.uuid')]" --field 'value' --value "'$uuid'"
|
|
}
|
|
|
|
update-module-list() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
set-addons-path
|
|
echo "env['ir.module.module'].update_list()" | odoo shell --database "$1" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
|
|
}
|
|
|
|
patch-database() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local filename="$2"
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
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'
|
|
}
|
|
|
|
# Report commands
|
|
|
|
cloc-odoo() {
|
|
local database="$1"
|
|
if [[ -z "$database" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
|
|
set-addons-path
|
|
odoo cloc -d "$database" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
|
|
}
|
|
|
|
visualize-dependencies() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
mkdir -p tmp
|
|
./bin/odoo-module-dependencies "$1"
|
|
open-with-os tmp/odoo-module-dependencies.html
|
|
cat tmp/odoo-module-dependencies.mmd
|
|
}
|
|
|
|
# Setup commands
|
|
|
|
install-requirements() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local file_path="$2"
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
file_path="$1"
|
|
fi
|
|
|
|
local file_name=$(basename "$file_path")
|
|
if ! [[ "$file_name" =~ .*requirements\.txt$ ]]; then
|
|
echo '$1 must point to requirements.txt file.'
|
|
exit
|
|
fi
|
|
|
|
local 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
|
|
echo 'Installing python packages in virutal env...'
|
|
uv pip install -r "$file_path"
|
|
fi
|
|
}
|
|
|
|
list-packages() {
|
|
uv pip list
|
|
}
|
|
|
|
generate-module-repo() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local repo_path="$1"
|
|
local 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 "$ODOO_VERSION"
|
|
|
|
echo "Remove all files from $repo_path"
|
|
rm -rf "$repo_path/*"
|
|
fi
|
|
|
|
echo "Copy template files from templates/$ODOO_VERSION to $repo_path"
|
|
cp "templates/$ODOO_VERSION/*" "$repo_path"
|
|
}
|
|
|
|
# Module commands
|
|
|
|
init-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local module_path="$2"
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
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
|
|
local modules=$(get-modules "$module_path" basename)
|
|
else
|
|
local modules=$(basename "$module_path")
|
|
fi
|
|
|
|
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 \
|
|
--log-level="$LOG_LEVEL"
|
|
}
|
|
|
|
update-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local module_name=$(basename "$2")
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
module_name=$(basename "$1")
|
|
fi
|
|
|
|
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
|
|
}
|
|
|
|
translate-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local module_path="$1"
|
|
local module_name=$(basename "$1")
|
|
local language="$2"
|
|
local database="$3"
|
|
|
|
if [[ -z "$2" ]]; then
|
|
language="$ODOO_LANGUAGE"
|
|
fi
|
|
|
|
if [[ -z "$3" ]]; then
|
|
database="$DB_NAME"
|
|
fi
|
|
|
|
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
|
|
}
|
|
|
|
test-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local module=$(basename "$1")
|
|
|
|
set-addons-path
|
|
echo "Testing module $module..."
|
|
odoo -d "$DB_NAME" -i "$module" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --test-tags /"$module_name"
|
|
}
|
|
|
|
test-modules() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local modules=$(get-modules "$1" basename)
|
|
set-addons-path
|
|
|
|
echo "Collect requirements.txt files in $1."
|
|
find "$1" -type f -name "requirements.txt" -exec uv pip install -r {} \;
|
|
|
|
echo "Collect test-requirements.txt files in $1."
|
|
find "$1" -type f -name "test-requirements.txt" -exec uv pip install -r {} \;
|
|
|
|
depends_modules=$(manifestoo --select-addons-dir "$1" list-depends --separator=,)
|
|
echo "Setup test database with "$ODOO_LANGUAGE" lang and depends modules: $depends_modules"
|
|
odoo -d "$DB_NAME" -i "$depends_modules" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$ODOO_LANGUAGE"
|
|
|
|
echo "Testing modules: $modules"
|
|
odoo -d "$DB_NAME" -i "$modules" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --test-enable
|
|
}
|
|
|
|
pytest-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
|
|
echo "Setup custom tmp/odoo.conf for pytest."
|
|
set-addons-path
|
|
local odoo_config="tmp/odoo.conf"
|
|
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"
|
|
|
|
echo "Run pytest with odoo-http option..."
|
|
pytest -s --odoo-http --odoo-config="$odoo_config" --odoo-database="$DB_NAME" "$module_path"
|
|
}
|
|
|
|
remove-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local module_name=$(basename "$2")
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
module_name=$(basename "$1")
|
|
fi
|
|
|
|
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
|
|
}
|
|
|
|
create-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local module_name=$(basename "$1")
|
|
local parent_dir=$(dirname "$1")
|
|
|
|
echo "Scaffolding module $module_name in ${parent_dir}..."
|
|
odoo scaffold "$module_name" "$parent_dir" -t templates/module
|
|
|
|
echo "Update summary and license in the '__manifest__.py'."
|
|
echo "Remove the 'security' folder if not required."
|
|
}
|
|
|
|
generate-module-docs() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
local manifest_path="$module_path/__manifest__.py"
|
|
|
|
echo 'Setup readme folder'
|
|
mkdir -p "$module_path/readme"
|
|
cp -n -r "templates/module/readme" "$module_path"
|
|
|
|
echo 'Update DESCRIPTION.rst'
|
|
export MODULE_SUMMARY=$(python3 -c "import ast; d=ast.literal_eval(open('$manifest_path').read()); print(d.get('summary', '').replace('\n', ' ').strip())")
|
|
envsubst < templates/module/readme/DESCRIPTION.md > "$module_path/readme/DESCRIPTION.md"
|
|
|
|
echo 'Update CONTRIBUTORS.rst'
|
|
export GIT_USER_NAME="$(git config user.name)"
|
|
export GIT_USER_EMAIL="$(git config user.email)"
|
|
envsubst < templates/module/readme/CONTRIBUTORS.md > "$module_path/readme/CONTRIBUTORS.md"
|
|
|
|
echo 'Copy icon.png'
|
|
cp templates/module/static/description/icon.png "$module_path/static/description/icon.png"
|
|
|
|
echo 'Copy LICENSE'
|
|
cp templates/module/LICENSE "$module_path/"
|
|
|
|
echo 'Touch __init__.py'
|
|
touch "$module_path/__init__.py"
|
|
|
|
echo "Generate OCA readme for $ORG_NAME org."
|
|
local repo_url=$(git -C "$(dirname $module_path)" remote get-url origin)
|
|
local repo_name=$(basename "${repo_url%.git}")
|
|
oca-gen-addon-readme --repo-name=$repo_name --branch=$ODOO_VERSION --org-name=$ORG_NAME --addon-dir=$module_path
|
|
}
|
|
|
|
generate-module-migration() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
local module_version=$(get-module-version $module_path)
|
|
|
|
echo "Create migrations folder for version $module_version."
|
|
mkdir -p "$module_path/migrations/$module_version"
|
|
|
|
echo "Copy pre-migrate template."
|
|
cp "templates/migrations/pre-migrate.py" "$module_path/migrations/$module_version"
|
|
}
|
|
|
|
generate-module-security() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local module_name=$(basename "$1")
|
|
local parent_dir=$(dirname "$1")
|
|
local model_dot_name="$2"
|
|
local model_name=$(echo "$model_dot_name" | tr '.' '_')
|
|
|
|
local 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"
|
|
}
|
|
|
|
generate-module-model() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
local module_name=$(basename "$1")
|
|
|
|
echo 'Substitute model template'
|
|
export MODEL_DOT_NAME="$2" # res.partner
|
|
export MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_') # res_partner
|
|
export NAME=$(echo "$MODEL_DOT_NAME" | cut -d"." -f2 | sed 's/[^_]\+/\L\u&/g') # Partners
|
|
export MODEL_DESCRIPTION=$(echo "$MODEL_NAME" | sed 's/[^_]\+/\L\u&/g' | sed 's/_/ /g') # Res Partner
|
|
export MODEL_CAMEL_NAME=$(echo "$MODEL_DESCRIPTION" | sed 's/ //g') # ResPartner
|
|
envsubst < templates/model.py > "$module_path/models/$MODEL_NAME.py"
|
|
echo "from . import $model_name" >> "$module_path/models/__init__.py"
|
|
echo "File "$module_path/models/$MODEL_NAME.py created.
|
|
}
|
|
|
|
generate-module-inherit() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
local module_name=$(basename "$1")
|
|
|
|
echo 'Substitute model template'
|
|
export MODEL_DOT_NAME="$2" # res.partner
|
|
export MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_') # res_partner
|
|
export NAME=$(echo "$MODEL_DOT_NAME" | cut -d"." -f2 | sed 's/[^_]\+/\L\u&/g') # Partners
|
|
export MODEL_DESCRIPTION=$(echo "$MODEL_NAME" | sed 's/[^_]\+/\L\u&/g' | sed 's/_/ /g') # Res Partner
|
|
export MODEL_CAMEL_NAME=$(echo "$MODEL_DESCRIPTION" | sed 's/ //g') # ResPartner
|
|
envsubst < templates/inherit.py > "$module_path/models/$MODEL_NAME.py"
|
|
echo "from . import $MODEL_NAME" >> "$module_path/models/__init__.py"
|
|
echo "File "$module_path/models/$MODEL_NAME.py created.
|
|
}
|
|
|
|
generate-module-views() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
local module_name=$(basename "$1")
|
|
|
|
echo 'Substitute view template'
|
|
mkdir -p "$module_path/views"
|
|
export MODEL_DOT_NAME="$2" # res.partner
|
|
export MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_') # res_partner
|
|
export NAME=$(echo "$MODEL_DOT_NAME" | cut -d"." -f2 | sed 's/[^_]\+/\L\u&/g') # Partners
|
|
export MODEL_DESCRIPTION=$(echo "$MODEL_NAME" | sed 's/[^_]\+/\L\u&/g' | sed 's/_/ /g') # Res Partner
|
|
export MODEL_CAMEL_NAME=$(echo "$MODEL_DESCRIPTION" | sed 's/ //g') # ResPartner
|
|
envsubst < 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\","
|
|
}
|
|
|
|
generate-module-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$3" ]]; then
|
|
echo '$3 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1" # addons/sale_workflow/sale_helm
|
|
|
|
echo 'Substitute snippet template'
|
|
export MODEL_DOT_NAME="$3" # sale.order
|
|
export VIEW_REF="$2" # sale.view_order_form
|
|
export MODEL_NAME=${MODEL_DOT_NAME//\./_}
|
|
export MODULE_NAME=$(basename "$1")
|
|
export SRC_MODULE_NAME=$(echo "$VIEW_REF" | cut -d"." -f1)
|
|
export XML_ID=$(echo "$VIEW_REF" | cut -d"." -f2)
|
|
mkdir -p "$module_path/views"
|
|
envsubst < templates/model_snippet.xml > "$module_path/views/${MODEL_NAME}_views.xml"
|
|
echo "Update file $MODULE_NAME/__manifest__.py with: \"views/${MODEL_NAME}_views.xml\""
|
|
}
|
|
|
|
release-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local version=$(get-module-version "$1")
|
|
cd "$1" || exit
|
|
local last_tag=$(git describe --tags)
|
|
local 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"
|
|
}
|
|
|
|
zip-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Get version and module name
|
|
local version=$(get-module-version "$1")
|
|
local module=$(basename "$1")
|
|
|
|
# Copy module to tmp folder
|
|
echo "Copy module $module version $version to tmp folder"
|
|
local module_name="$module-$version"
|
|
local 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
|
|
}
|
|
|
|
# Upgrade commands
|
|
|
|
migrate-module() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
local module_path="$1"
|
|
local source_odoo_version=$(get-module-version $module_path | cut -d'.' -f1,2)
|
|
|
|
if [[ "$ODOO_VERSION" == "19.0" ]]; then
|
|
local module=$(basename "$module_path")
|
|
local addons_path=$(dirname "$module_path")
|
|
|
|
echo "Run Odoo upgrade_code command for $module_path from ${source_odoo_version}..."
|
|
odoo upgrade_code --addons-path "$addons_path" --from "$source_odoo_version"
|
|
|
|
echo "Replace manifest version $source_odoo_version with $ODOO_VERSION."
|
|
sed -i -E "s/$source_odoo_version/$ODOO_VERSION/g" "$module_path/__manifest__.py"
|
|
else
|
|
echo "Run odoo-module-migrator for $module with source $source_odoo_version and target ${ODOO_VERSION}..."
|
|
odoo-module-migrate --directory $(dirname "$module_path") --modules $(basename "$module_path") \
|
|
--init-version-name $source_odoo_version --target-version-name $ODOO_VERSION --no-commit
|
|
fi
|
|
}
|
|
|
|
upgrade-odoo() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ "$1" =~ "list" ]]; then
|
|
echo "info"
|
|
echo "all-test"
|
|
echo "all-production"
|
|
echo "dump"
|
|
echo "filestore"
|
|
echo "drop"
|
|
echo "upgrade-test"
|
|
echo "upgrade-production"
|
|
echo "clear-assets"
|
|
echo "init"
|
|
echo "uninstall"
|
|
echo "auto-update"
|
|
echo "update"
|
|
echo "configure-test"
|
|
echo "configure-production"
|
|
echo "restart"
|
|
echo "logs"
|
|
echo "shell"
|
|
echo "psql"
|
|
echo "rename-production"
|
|
echo "stop-container"
|
|
echo "browse"
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
load-dotenv "$1"
|
|
temp_folder="/var/tmp"
|
|
|
|
# Setup ssh aliases
|
|
ssh_server="ssh -p $PORT $SERVER"
|
|
ssh_target_server="ssh -t -p $TARGET_PORT $TARGET_SERVER"
|
|
scp_exec="scp"
|
|
if [[ -n "$JUMP_HOST" ]]; then
|
|
log-warning "Source connection uses jump host: $JUMP_HOST"
|
|
ssh_server="ssh -p $PORT -J $JUMP_HOST $SERVER"
|
|
scp_exec="scp -o ProxyJump=$JUMP_HOST"
|
|
fi
|
|
if [[ -n "$TARGET_JUMP_HOST" ]]; then
|
|
log-warning "Target connection uses jump host: $JUMP_HOST"
|
|
ssh_target_server="ssh -t -p $TARGET_PORT -J $TARGET_JUMP_HOST $TARGET_SERVER"
|
|
fi
|
|
|
|
if [[ "$2" =~ "info" ]]; then
|
|
echo ""
|
|
echo "Source Enviroment"
|
|
echo "-----------------"
|
|
echo "Host: $HOST"
|
|
echo "Server: $SERVER:$PORT"
|
|
echo "Jump Host: $JUMP_HOST"
|
|
echo "Odoo Container: $ODOO_CONTAINER"
|
|
echo "Odoo Version: $ODOO_VERSION"
|
|
echo "Postgres Container: $POSTGRES_CONTAINER"
|
|
echo "Database: $DATABASE"
|
|
echo ""
|
|
echo "Target Enviroment"
|
|
echo "-----------------"
|
|
echo "Host: $TARGET_HOST"
|
|
echo "Server: $TARGET_SERVER:$TARGET_PORT"
|
|
echo "Jump Host: $TARGET_JUMP_HOST"
|
|
echo "Odoo Container: $TARGET_ODOO_CONTAINER"
|
|
echo "Odoo Version: $TARGET_ODOO_VERSION"
|
|
echo "Postgres Container: $TARGET_POSTGRES_CONTAINER"
|
|
echo "Database: $TARGET_DATABASE"
|
|
echo ""
|
|
echo "Upgrade Configuration"
|
|
echo "---------------------"
|
|
echo "Init Addons: $ODOO_ADDONS_INIT"
|
|
echo "Uninstall Addons: $ODOO_ADDONS_UNINSTALL"
|
|
echo ""
|
|
echo "Test Config: $ODOO_CONFIGURE_TEST"
|
|
echo "Production Config: $ODOO_CONFIGURE_PRODUCTION"
|
|
echo ""
|
|
fi
|
|
|
|
if [[ "$2" =~ "all-test" ]]; then
|
|
echo "#FIXME: implement this command."
|
|
fi
|
|
|
|
|
|
if [[ "$2" =~ "all-production" ]]; then
|
|
echo "#FIXME: implement this command."
|
|
fi
|
|
|
|
if [[ "$2" =~ "dump" ]]; then
|
|
log-warning "Run step 'dump' on $SERVER."
|
|
|
|
$ssh_server sudo docker-postgres-backup -c "$POSTGRES_CONTAINER" -d "$DATABASE" -o "$temp_folder"
|
|
|
|
if [[ "$SERVER" != "$TARGET_SERVER" ]]; then
|
|
log-warning "Source and target host are different."
|
|
|
|
echo "Copy dump from $SERVER to $TARGET_SERVER..."
|
|
$ssh_target_server mkdir -p "$temp_folder/$TARGET_POSTGRES_CONTAINER"
|
|
$scp_exec "$SERVER:$temp_folder/$POSTGRES_CONTAINER/$DATABASE.sql" "$TARGET_SERVER:$temp_folder/$TARGET_POSTGRES_CONTAINER/$DATABASE.sql"
|
|
$ssh_target_server sudo docker-postgres-restore -c "$TARGET_POSTGRES_CONTAINER" -d "$DATABASE" -f "$temp_folder/$TARGET_POSTGRES_CONTAINER/$DATABASE.sql" -r
|
|
else
|
|
$ssh_target_server sudo docker-postgres-restore -c "$TARGET_POSTGRES_CONTAINER" -d "$DATABASE" -f "$temp_folder/$POSTGRES_CONTAINER/$DATABASE.sql" -r
|
|
fi
|
|
fi
|
|
|
|
if [[ "$2" =~ "filestore" ]]; then
|
|
log-warning "Run step 'filestore' on $SERVER."
|
|
|
|
$ssh_server docker-export -c "$ODOO_CONTAINER" -p "/var/lib/odoo/filestore/$DATABASE" -o "$temp_folder"
|
|
|
|
if [[ "$SERVER" != "$TARGET_SERVER" ]]; then
|
|
log-warning "Source and target host are different."
|
|
|
|
echo "Copy filestore from $SERVER to $TARGET_SERVER..."
|
|
$scp_exec "$SERVER:$temp_folder/$ODOO_CONTAINER.tar" "$TARGET_SERVER:$temp_folder/$TARGET_ODOO_CONTAINER.tar"
|
|
$ssh_target_server docker-import -c "$TARGET_ODOO_CONTAINER" -p "/var/lib/odoo/filestore/$TARGET_DATABASE" -f "$temp_folder/$TARGET_ODOO_CONTAINER.tar" -r
|
|
else
|
|
$ssh_target_server docker-import -c "$TARGET_ODOO_CONTAINER" -p "/var/lib/odoo/filestore/$TARGET_DATABASE" -f "$temp_folder/$ODOO_CONTAINER.tar" -r
|
|
fi
|
|
fi
|
|
|
|
if [[ "$2" = "drop" ]]; then
|
|
log-warning "Run step 'drop' on $TARGET_SERVER."
|
|
$ssh_target_server docker-postgres-drop -c "$TARGET_POSTGRES_CONTAINER" -d "$TARGET_DATABASE"
|
|
fi
|
|
|
|
if [[ "$2" = "upgrade-test" ]]; then
|
|
log-warning "Run step 'upgrade-test' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-upgrade -c "$TARGET_POSTGRES_CONTAINER" -d "$DATABASE" -s "$ODOO_VERSION" -n "$TARGET_DATABASE" -t "$TARGET_ODOO_VERSION"
|
|
fi
|
|
|
|
if [[ "$2" = "upgrade-production" ]]; then
|
|
log-warning "Run step 'upgrade-production' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-upgrade -m production -c "$TARGET_POSTGRES_CONTAINER" -d "$DATABASE" -s "$ODOO_VERSION" -n "$TARGET_DATABASE" -t "$TARGET_ODOO_VERSION"
|
|
fi
|
|
|
|
if [[ "$2" = "clear-assets" ]]; then
|
|
log-warning "Run step 'clear-assets' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-clear-assets -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE"
|
|
fi
|
|
|
|
if [[ "$2" = "init" ]]; then
|
|
log-warning "Run step 'init' on $TARGET_SERVER."
|
|
if [[ -n "$ODOO_ADDONS_INIT" ]]; then
|
|
$ssh_target_server docker-odoo-init -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE" -i "$ODOO_ADDONS_INIT"
|
|
else
|
|
echo "Nothing to do."
|
|
fi
|
|
fi
|
|
|
|
if [[ "$2" = "uninstall" ]]; then
|
|
log-warning "Run step 'uninstall' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-uninstall -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE" -u "$ODOO_ADDONS_UNINSTALL"
|
|
fi
|
|
|
|
if [[ "$2" = "auto-update" ]]; then
|
|
log-warning "Run step 'auto-update' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-shell -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE" -f -p "env['ir.module.module'].upgrade_changed_checksum()"
|
|
fi
|
|
|
|
if [[ "$2" = "update" ]]; then
|
|
log-warning "Run step 'update' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-update -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE" -u all
|
|
fi
|
|
|
|
if [[ "$2" = "configure-test" ]]; then
|
|
log-warning "Run step 'configure' on $TARGET_SERVER."
|
|
if [[ -n "$ODOO_CONFIGURE_TEST" ]]; then
|
|
$ssh_target_server docker-odoo-shell -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE" -f -p "\"$ODOO_CONFIGURE_TEST\""
|
|
else
|
|
echo "Nothing to do."
|
|
fi
|
|
fi
|
|
|
|
if [[ "$2" = "configure-production" ]]; then
|
|
log-warning "Run step 'configure' on $TARGET_SERVER."
|
|
if [[ -n "$ODOO_CONFIGURE_PRODUCTION" ]]; then
|
|
$ssh_target_server docker-odoo-shell -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE" -f -p "\"$ODOO_CONFIGURE_PRODUCTION\""
|
|
else
|
|
echo "Nothing to do."
|
|
fi
|
|
fi
|
|
|
|
if [[ "$2" = "restart" ]]; then
|
|
log-warning "Run step 'restart' on $TARGET_SERVER."
|
|
$ssh_target_server docker restart "$TARGET_ODOO_CONTAINER" "$TARGET_POSTGRES_CONTAINER"
|
|
fi
|
|
|
|
if [[ "$2" = "logs" ]]; then
|
|
log-warning "Run step 'logs' on $TARGET_SERVER."
|
|
containe_id=$($ssh_target_server docker ps -f "name=$TARGET_ODOO_CONTAINER" --format '{{.ID}}' | head -n1)
|
|
$ssh_target_server docker logs -f "$containe_id" --tail 10
|
|
fi
|
|
|
|
if [[ "$2" = "shell" ]]; then
|
|
log-warning "Run step 'shell' on $TARGET_SERVER."
|
|
$ssh_target_server docker-odoo-shell -c "$TARGET_ODOO_CONTAINER" -d "$TARGET_DATABASE"
|
|
fi
|
|
|
|
if [[ "$2" = "psql" ]]; then
|
|
log-warning "Run step 'psql' on $TARGET_SERVER."
|
|
$ssh_target_server docker-postgres-shell -c "$TARGET_POSTGRES_CONTAINER" -d "$TARGET_DATABASE"
|
|
fi
|
|
|
|
if [[ "$2" = "env" ]]; then
|
|
log-warning "Run step 'env' on $TARGET_SERVER."
|
|
containe_id=$($ssh_target_server docker ps -f "name=$TARGET_ODOO_CONTAINER" --format '{{.ID}}' | head -n1)
|
|
$ssh_target_server docker exec "$containe_id" env
|
|
fi
|
|
|
|
if [[ "$2" = "conf" ]]; then
|
|
log-warning "Run step 'conf' on $TARGET_SERVER."
|
|
containe_id=$($ssh_target_server docker ps -f "name=$TARGET_ODOO_CONTAINER" --format '{{.ID}}' | head -n1)
|
|
$ssh_target_server docker exec "$containe_id" cat /etc/odoo/odoo.conf
|
|
fi
|
|
|
|
if [[ "$2" = "stop-container" ]]; then
|
|
log-warning "Run step 'stop-container' on $TARGET_SERVER."
|
|
$ssh_server docker stop "$ODOO_CONTAINER"
|
|
fi
|
|
|
|
if [[ "$2" = "rename-production" ]]; then
|
|
log-warning "Run step 'rename-production' on $TARGET_SERVER."
|
|
if [[ "$POSTGRES_CONTAINER" != "$TARGET_POSTGRES_CONTAINER" ]]; then
|
|
if [[ "$DATABASE" = "odoo" ]]; then
|
|
$ssh_server docker-postgres-rename -c "$TARGET_POSTGRES_CONTAINER" -s "$DATABASE" -t "${DATABASE}-old"
|
|
fi
|
|
$ssh_server docker-postgres-rename -c "$TARGET_POSTGRES_CONTAINER" -s "$TARGET_DATABASE" -t "$DATABASE"
|
|
else
|
|
$ssh_server docker-postgres-rename -c "$TARGET_POSTGRES_CONTAINER" -s "$DATABASE" -t "${DATABASE}-old"
|
|
$ssh_server docker-postgres-rename -c "$TARGET_POSTGRES_CONTAINER" -s "$TARGET_DATABASE" -t "$DATABASE"
|
|
fi
|
|
$ssh_server docker-postgres-list -c "$TARGET_POSTGRES_CONTAINER"
|
|
|
|
if [[ "$DATABASE" = "odoo" ]]; then
|
|
$ssh_server docker exec "$TARGET_ODOO_CONTAINER" mv "/var/lib/odoo/filestore/$DATABASE" "/var/lib/odoo/filestore/$DATABASE-old"
|
|
fi
|
|
$ssh_server docker exec "$TARGET_ODOO_CONTAINER" mv "/var/lib/odoo/filestore/$TARGET_DATABASE" "/var/lib/odoo/filestore/$DATABASE"
|
|
fi
|
|
|
|
if [[ "$2" = "browse" ]]; then
|
|
log-warning "Run step '$2' on $TARGET_SERVER."
|
|
open-url-with-delay "https://$TARGET_HOST" 0
|
|
fi
|
|
|
|
}
|
|
|
|
# Snippet commands
|
|
|
|
reset-views() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
local database="$1"
|
|
local key=$(basename "$2")
|
|
|
|
# Use default database if second param is not given
|
|
if [[ -z "$2" ]]; then
|
|
database="$DB_NAME"
|
|
key=$(basename "$1")
|
|
fi
|
|
|
|
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
|
|
}
|
|
|
|
create-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
export INHERIT_ID=$(echo "$1" | cut -d. -f1-2)
|
|
local file="snippets/$SNIPPET_PREFIX.$1.xml"
|
|
|
|
echo "Create snippet from template: $file"
|
|
envsubst '$INHERIT_ID' < templates/snippet.xml > "$file"
|
|
}
|
|
|
|
install-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Generate view name from filename
|
|
local file=$(basename "$2")
|
|
local name="${file%.xml}"
|
|
local inherit_id=$(echo 'cat //data/@inherit_id' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local type=$(echo 'cat //data/@type' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local model=$(echo 'cat //data/@model' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local priority=$(echo 'cat //data/@priority' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local module_name=$(echo "$inherit_id" | cut -d. -f 1 )
|
|
local xml_id=$(echo "$inherit_id" | cut -d. -f 2 )
|
|
|
|
# Set default values
|
|
: ${type:='qweb'}
|
|
|
|
load-dotenv "$1"
|
|
echo "Search for view with name $module_name.$xml_id"
|
|
inherit_id=$(images/odoocli/bin/odoocli --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"
|
|
images/odoocli/bin/odoocli --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")'''
|
|
}"
|
|
}
|
|
|
|
update-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Generate view name from filename
|
|
local file=$(basename "$2")
|
|
local name="${file%.xml}"
|
|
|
|
load-dotenv "$1"
|
|
echo "Update view with name $name"
|
|
images/odoocli/bin/odoocli --method 'write' --model 'ir.ui.view' --include-archived --domain "[('name', '=', '$name')]" --field 'arch_base' --value "'''$(cat "$2")'''"
|
|
enable-snippet "$1" "$2"
|
|
}
|
|
|
|
disable-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Get name from path
|
|
# path: snippets/mint_system.base.view_partner_tree.show_type.xml
|
|
# name: mint_system.base.view_partner_tree.show_type
|
|
local name="$2"
|
|
if [[ "$2" == *.xml ]]; then
|
|
local file=$(basename "$2")
|
|
name="${file%.xml}"
|
|
fi
|
|
|
|
load-dotenv "$1"
|
|
echo "Disable view with name $name"
|
|
images/odoocli/bin/odoocli --method 'write' --model "ir.ui.view" --domain "[('name', '=', '$name')]" --field "active" --value "False"
|
|
}
|
|
|
|
enable-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Get name from path
|
|
local name="$2"
|
|
if [[ "$2" == *.xml ]]; then
|
|
local file=$(basename "$2")
|
|
name="${file%.xml}"
|
|
fi
|
|
|
|
load-dotenv "$1"
|
|
echo "Enable view with name $name"
|
|
images/odoocli/bin/odoocli --method 'write' --model "ir.ui.view" --include-archived --domain "[('name', '=', '$name')]" --field "active" --value "True"
|
|
}
|
|
|
|
remove-snippet() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Get name from path
|
|
local name="$2"
|
|
if [[ "$2" == *.xml ]]; then
|
|
local file=$(basename "$2")
|
|
name="${file%.xml}"
|
|
fi
|
|
|
|
load-dotenv "$1"
|
|
echo "Remove view with name $name"
|
|
images/odoocli/bin/odoocli --method "unlink" --model "ir.ui.view" --domain "[('name', '=', '$name')]"
|
|
}
|
|
|
|
lint-snippets() {
|
|
echo 'Lint snippets files...'
|
|
|
|
local files="snippets/*.xml"
|
|
|
|
for file in $files; do
|
|
|
|
# Access various snippet parameters
|
|
local filename=$(basename "$file")
|
|
local snippet_module=$(echo "$filename" | cut -d. -f2)
|
|
local report=$(echo "$filename" | cut -d. -f3)
|
|
local edit=$(echo "$filename" | cut -d. -f4)
|
|
local inherit_id=$(echo 'cat //data/@inherit_id' | xmllint --shell "$file" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local type=$(echo 'cat //data/@type' | xmllint --shell "$file" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local model=$(echo 'cat //data/@model' | xmllint --shell "$file" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local priority=$(echo 'cat //data/@priority' | xmllint --shell "$file" | awk -F'[="]' '!/>/{print $(NF-1)}')
|
|
local module_name=$(echo "$inherit_id" | cut -d. -f 1 )
|
|
local xml_id=$(echo "$inherit_id" | cut -d. -f 2 )
|
|
|
|
# Check filename
|
|
local count_dots=$(echo "$filename" | grep -o "\." | wc -l)
|
|
if [[ "$count_dots" -ge 5 ]]; 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
|
|
|
|
add-git-folder() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
if [[ -z "$2" ]]; then
|
|
echo '$2 is empty.'
|
|
exit
|
|
fi
|
|
|
|
# Add to .gitmodules
|
|
git submodule add -f -b "$ODOO_VERSION" "$1" "$2"
|
|
|
|
# Ensure branch is Odoo version
|
|
git -C "$2" switch "$ODOO_VERSION"
|
|
|
|
# Save version
|
|
save-version
|
|
|
|
# Restore staged submodule files
|
|
git restore --staged .gitmodules "$2"
|
|
|
|
# Remove from working tree
|
|
# rm -rf .git/modules/"$2" || true
|
|
# git rm --cached "$2" || true
|
|
}
|
|
|
|
aggregate-git-folders() {
|
|
if [[ -z "$1" ]]; then
|
|
echo '$1 is empty.'
|
|
exit
|
|
fi
|
|
|
|
gitaggregate -c "$1" --expand-env
|
|
}
|
|
|
|
ls-git-folder() {
|
|
if [[ -n "$1" ]]; then
|
|
echo $(git config --file .gitmodules --get-regexp url | sed -e 's/submodule.//g' -e 's/.url.*//g' | grep "$1" | sort)
|
|
else
|
|
echo $(git config --file .gitmodules --get-regexp url | sed -e 's/submodule.//g' -e 's/.url.*//g' | sort)
|
|
fi
|
|
}
|
|
|
|
list-git-folder() {
|
|
# Define column widths
|
|
local path_width=35
|
|
local url_width=50
|
|
local branch_width=8
|
|
|
|
# Print table header
|
|
printf "| %-${path_width}s | %-${url_width}s | %-${branch_width}s |\n" "PATH" "URL" "BRANCH"
|
|
echo "|$(printf '%*s' $((path_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((url_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((branch_width + 2)) '' | tr ' ' '-')|"
|
|
|
|
local git_folders=$(ls-git-folder "$1")
|
|
for git_folder in $git_folders; do
|
|
local url=$(git config --file .gitmodules --get "submodule.$git_folder.url")
|
|
url=${url#git@github.com:}
|
|
url=${url%.git}
|
|
local branch=$(git -C "$git_folder" branch --show-current 2>/dev/null || echo "detached")
|
|
printf "| %-${path_width}s | %-${url_width}s | %-${branch_width}s |\n" "$git_folder" "$url" "${branch:-detached}"
|
|
done
|
|
}
|
|
|
|
remove-git-folder() {
|
|
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
|
|
local git_folders=$(ls-git-folder "$1")
|
|
|
|
echo "Delete: $git_folders"
|
|
read -p "Are you sure to delete these git folder(s)? (yes/N): " confirm
|
|
if [[ "${confirm,,}" != "yes" ]]; then
|
|
echo 'Aborted.'
|
|
return 1
|
|
fi
|
|
for git_folder in $git_folders; do
|
|
echo "Remove $git_folder from .gitmodules file."
|
|
git config --file .gitmodules --remove-section "submodule.$git_folder"
|
|
|
|
echo "Delete git folder $git_folder."
|
|
rm -rf "$git_folder"
|
|
done
|
|
|
|
save-version
|
|
}
|
|
|
|
clone-git-folder() {
|
|
local git_folders=$(ls-git-folder "$1")
|
|
for git_folder in $git_folders; do
|
|
|
|
local git_folder_path=$(git config --file .gitmodules --get submodule."$git_folder".path)
|
|
local git_folder_url=$(git config --file .gitmodules --get submodule."$git_folder".url)
|
|
local shallow=$(git config --file .gitmodules --get submodule."$git_folder".shallow)
|
|
local git_folder_branch=$(git config --file .gitmodules --get submodule."$git_folder".branch)
|
|
|
|
if [[ "$shallow" = "true" ]]; then
|
|
echo "Clone git folder $git_folder (shallow) with $git_folder_branch branch"
|
|
git -C "$git_folder" config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
|
|
git clone --depth 1 --no-single-branch "$git_folder_url" "$git_folder_path"
|
|
else
|
|
echo "Clone git folder $git_folder with $git_folder_branch branch"
|
|
git clone --branch="$git_folder_branch" "$git_folder_url" "$git_folder_path"
|
|
fi
|
|
done
|
|
}
|
|
|
|
download-git-folder() {
|
|
local git_folders=$(ls-git-folder "$1")
|
|
for git_folder in $git_folders; do
|
|
|
|
local git_folder_path=$(git config --file .gitmodules --get submodule."$git_folder".path)
|
|
local git_folder_url=$(git config --file .gitmodules --get submodule."$git_folder".url)
|
|
local git_folder_branch=$(git config --file .gitmodules --get submodule."$git_folder".branch)
|
|
|
|
# Convert git url to http url.
|
|
git_folder_url="$(echo $git_folder_url | sed 's|git@|https://|g' | sed 's|m:|m/|g' | sed 's|\.git||g')"
|
|
|
|
# Get commit ref from .gitmodule.csv
|
|
local commit_ref=$(grep "$git_folder_path" "versions/$ODOO_VERSION/.gitmodules.csv" | cut -d',' -f2)
|
|
|
|
echo "Download $git_folder_url to $git_folder_path."
|
|
mkdir -p "$git_folder_path"
|
|
curl -L -o "$git_folder_path/archive.tar.gz" \
|
|
"$git_folder_url/archive/$commit_ref.tar.gz"
|
|
|
|
echo "Extract and delete $git_folder_path/archive.tar.gz"
|
|
tar -xzf "$git_folder_path/archive.tar.gz" --strip-components=1 -C "$git_folder_path"
|
|
rm "$git_folder_path/archive.tar.gz"
|
|
done
|
|
}
|
|
|
|
checkout-git-folder() {
|
|
local git_folders=$(ls-git-folder)
|
|
for git_folder in $git_folders; do
|
|
|
|
local shallow=$(git config --file .gitmodules --get submodule."$git_folder".shallow)
|
|
local commit_ref=$(grep "$git_folder" "versions/$ODOO_VERSION/.gitmodules.csv" | cut -d',' -f2)
|
|
|
|
if [[ "$shallow" = "true" ]]; then
|
|
echo "Checkout git folder $git_folder (shallow) to $commit_ref"
|
|
git -C "$git_folder" stash
|
|
git -C "$git_folder" fetch origin "$ODOO_VERSION:$ODOO_VERSION"
|
|
git -C "$git_folder" checkout "$commit_ref"
|
|
else
|
|
echo "Checkout git folder $git_folder to $commit_ref"
|
|
git -C "$git_folder" stash
|
|
git -C "$git_folder" checkout "$commit_ref"
|
|
fi
|
|
done
|
|
}
|
|
|
|
switch-git-folder() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_VERSION="$1"
|
|
fi
|
|
|
|
local git_folders=$(ls-git-folder)
|
|
for git_folder in $git_folders; do
|
|
|
|
local shallow=$(git config --file .gitmodules --get submodule."$git_folder".shallow)
|
|
|
|
if [[ "$shallow" = "true" ]]; then
|
|
echo "Fetch branch $ODOO_VERSION (shallow) from origin and then switch."
|
|
git -C "$git_folder" fetch origin "$ODOO_VERSION:$ODOO_VERSION"
|
|
git -C "$git_folder" switch "$ODOO_VERSION"
|
|
else
|
|
echo "Switch git folder branch to $ODOO_VERSION: $git_folder"
|
|
git -C "$git_folder" stash
|
|
git -C "$git_folder" switch "$ODOO_VERSION"
|
|
fi
|
|
done
|
|
}
|
|
|
|
pull-git-folder() {
|
|
local git_folders=$(ls-git-folder)
|
|
for git_folder in $git_folders; do
|
|
echo "Pull git folder $git_folder."
|
|
git -C "$git_folder" stash
|
|
local update=$(git config submodule."$git_folder".update)
|
|
if [[ -z "$update" ]]; then
|
|
git -C "$git_folder" pull origin "$ODOO_VERSION"
|
|
fi;
|
|
done
|
|
}
|
|
|
|
sync-git-folder() {
|
|
echo 'Switch and pull git folders.'
|
|
switch-git-folder
|
|
pull-git-folder
|
|
}
|
|
|
|
create-git-feature-branch(){
|
|
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
|
|
|
|
local module_name=$(basename "$1")
|
|
local 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"
|
|
}
|
|
|
|
create-git-mig-branch(){
|
|
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
|
|
|
|
local module_name=$(basename "$1")
|
|
local module_path=$(dirname "$1")
|
|
|
|
echo "Create mig branch for $module_name in ${module_path}..."
|
|
cd ./"$module_path" || exit
|
|
pwd
|
|
git switch -c "$ODOO_VERSION-mig-$module_name"
|
|
}
|
|
|
|
# Project commands
|
|
|
|
load-version() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_VERSION="$1"
|
|
fi
|
|
|
|
echo "Copy .gitmodules and .python-version from 'versions/$ODOO_VERSION'."
|
|
cp "versions/$ODOO_VERSION/.gitmodules" .
|
|
cp "versions/$ODOO_VERSION/.python-version" .
|
|
}
|
|
|
|
checkout() {
|
|
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
|
|
ODOO_VERSION="$1"
|
|
|
|
# Load .gitmodules and .python-version
|
|
load-version "$ODOO_VERSION"
|
|
# Set .env
|
|
load-revision "$ODOO_VERSION"
|
|
# Clone the addons
|
|
clone-git-folder
|
|
# Checkout commit ref
|
|
checkout-git-folder
|
|
# Upate branch
|
|
switch-git-folder
|
|
}
|
|
|
|
save-version() {
|
|
local git_folders_file="versions/$ODOO_VERSION/.gitmodules.csv"
|
|
echo "Save git refs to $git_folders_file."
|
|
|
|
local git_folders=$(ls-git-folder)
|
|
echo "path,rev" > "$git_folders_file"
|
|
for git_folder in $git_folders; do
|
|
local commit_ref=$(git -C "$git_folder" rev-parse HEAD)
|
|
echo "$git_folder,$commit_ref" >> "$git_folders_file"
|
|
done
|
|
|
|
echo "Copy .gitmodules and .python-version to 'versions/$ODOO_VERSION'"
|
|
cp ".gitmodules" "versions/$ODOO_VERSION/"
|
|
cp ".python-version" "versions/$ODOO_VERSION/"
|
|
}
|
|
|
|
|
|
list-versions() {
|
|
ls -1 versions
|
|
}
|
|
|
|
check-version() {
|
|
echo 'Check if Odoo version matches the release file:'
|
|
local odoo_version=$(echo "$ODOO_VERSION" | cut -d'.' -f1)
|
|
grep -E "version_info.+$odoo_version" odoo/odoo/release.py
|
|
}
|
|
|
|
# Revision commands
|
|
|
|
list-revision() {
|
|
ls -1 revisions
|
|
}
|
|
|
|
show-revision() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_REVISION="$1"
|
|
fi
|
|
|
|
echo "Odoo Revision: $ODOO_REVISION"
|
|
source "revisions/$ODOO_REVISION"
|
|
|
|
echo "Odoo Ref: $ODOO_REF"
|
|
echo "Odoo Enterprise Ref: $ODOO_ENTERPRISE_REF"
|
|
echo "Odoo Themes Ref: $ODOO_THEME_REF"
|
|
}
|
|
|
|
load-revision() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_REVISION="$1"
|
|
fi
|
|
|
|
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 "revisions/$ODOO_REVISION" | sed 's/#.*//g' | xargs)
|
|
}
|
|
|
|
checkout-revision() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_REVISION="$1"
|
|
fi
|
|
|
|
load-revision "$ODOO_REVISION"
|
|
|
|
echo 'Checkout Odoo git repos...'
|
|
git -C odoo checkout $ODOO_REF
|
|
git -C enterprise checkout $ODOO_ENTERPRISE_REF
|
|
git -C themes checkout $ODOO_THEME_REF
|
|
}
|
|
|
|
create-revision() {
|
|
if [[ -z "$1" ]]; then echo "\$1 is empty."; exit; fi
|
|
|
|
local revision="$1"
|
|
local odoo_date=$(echo "$revision" | cut -d'.' -f3-)
|
|
local before_date=$(date -d "$odoo_date -1 day" +"%Y-%m-%d")
|
|
echo "Checkout Odoo repos on $before_date."
|
|
|
|
# Get git commit by date
|
|
cd odoo
|
|
git fetch
|
|
echo -e "\nShow last 3 commits from $before_date:"
|
|
git --no-pager log -n 3 --pretty=format:"%h %ad %s" --date=short --before="$before_date" origin/$ODOO_VERSION
|
|
local ref=$(git rev-list -n 1 --before="$before_date" origin/$ODOO_VERSION)
|
|
git checkout "$ref"
|
|
cd ..
|
|
|
|
cd enterprise
|
|
git fetch
|
|
echo -e "\nShow last 3 commits from $before_date:"
|
|
git --no-pager log -n 3 --pretty=format:"%h %ad %s" --date=short --before="$before_date" origin/$ODOO_VERSION
|
|
local enterprise_ref=$(git rev-list -n 1 --before="$before_date" origin/$ODOO_VERSION)
|
|
git checkout "$enterprise_ref"
|
|
cd ..
|
|
|
|
cd themes
|
|
git fetch
|
|
echo -e "\nShow last 3 commits from $before_date:"
|
|
git --no-pager log -n 3 --pretty=format:"%h %ad %s" --date=short --before="$before_date" origin/$ODOO_VERSION
|
|
local theme_ref=$(git rev-list -n 1 --before="$before_date" origin/$ODOO_VERSION)
|
|
git checkout "$theme_ref"
|
|
cd ..
|
|
|
|
echo -e "\nCreate revision: $revision"
|
|
export ODOO_REVISION=$revision
|
|
export ODOO_REF=$ref
|
|
export ODOO_ENTERPRISE_REF=$enterprise_ref
|
|
export ODOO_THEME_REF=$theme_ref
|
|
envsubst < templates/odoo_revision > "revisions/$revision"
|
|
chmod +x "revisions/$revision"
|
|
|
|
echo "Checkout revision: $revision"
|
|
checkout-revision "$revision"
|
|
}
|
|
|
|
commit-and-push-revision() {
|
|
if [[ -n "$1" ]]; then
|
|
ODOO_REVISION="$1"
|
|
fi
|
|
|
|
echo 'Remove existing tag...'
|
|
git tag -d "$ODOO_REVISION"
|
|
|
|
echo "Commit with revision $ODOO_REVISION tag..."
|
|
git commit --all --message "feat(revision): release $ODOO_REVISION"
|
|
git tag "$ODOO_REVISION"
|
|
|
|
echo 'Push tags...'
|
|
git push
|
|
git push -f --tags
|
|
}
|
|
|
|
# RPC commands
|
|
|
|
test-xmlrpc() {
|
|
load-dotenv "$1"
|
|
echo "Connect to database and count res.partner records: $(images/odoocli/bin/odoocli --model 'res.partner' --method 'search_count' --domain '[]')"
|
|
}
|
|
|
|
odoocli(){
|
|
images/odoocli/bin/odoocli "$@"
|
|
}
|
|
|
|
manifestoo(){
|
|
set-addons-path
|
|
./.venv$ODOO_VERSION/bin/manifestoo --addons-path="$ADDONS_PATH" "$@"
|
|
}
|
|
|
|
export-website-data() {
|
|
if [[ -n "$1" ]]; then
|
|
load-dotenv $1
|
|
fi
|
|
|
|
export ODOO_URL
|
|
export DB_NAME
|
|
export ODOO_USERNAME
|
|
export ODOO_PASSWORD
|
|
export ODOO_WEBSITE_ID
|
|
|
|
echo -e "\nPython Output:\n\n---"
|
|
python "bin/export-website-data"
|
|
local exit_code=$?
|
|
echo -e "---\n"
|
|
echo -e "Exit code: $exit_code\n"
|
|
}
|
|
|
|
import-website-data() {
|
|
if [[ -n "$1" ]]; then
|
|
load-dotenv $1
|
|
fi
|
|
|
|
export ODOO_URL
|
|
export DB_NAME
|
|
export ODOO_USERNAME
|
|
export ODOO_PASSWORD
|
|
export ODOO_WEBSITE_ID
|
|
|
|
echo -e "\nPython Output:\n\n---"
|
|
python "bin/import-website-data"
|
|
local exit_code=$?
|
|
echo -e "---\n"
|
|
echo -e "Exit code: $exit_code\n"
|
|
}
|
|
|
|
# Vuepress commands
|
|
|
|
install-vuepress() {
|
|
echo 'Install Node.'
|
|
pnpm env use --global lts
|
|
|
|
echo 'Install npm packages.'
|
|
pnpm install
|
|
}
|
|
|
|
dev-vuepress() {
|
|
pnpm run dev
|
|
}
|
|
|
|
build-vuepress() {
|
|
pnpm run build
|
|
|
|
echo "Create vuepress snippets folders."
|
|
mkdir -p .vuepress/dist/snippets
|
|
|
|
echo "Copy snippet files to snippets folder."
|
|
cp snippets/*.xml .vuepress/dist/snippets
|
|
}
|
|
|
|
serve-vuepress() {
|
|
cd .vuepress/dist
|
|
pnpx serve
|
|
}
|
|
|
|
if [[ "$1" == *","* ]]; then
|
|
# Split comma-separated commands
|
|
IFS=',' read -ra COMMANDS <<< "$1"
|
|
for cmd in "${COMMANDS[@]}"; do
|
|
# Trim whitespace
|
|
cmd=$(echo "$cmd" | xargs)
|
|
if declare -f "$cmd" > /dev/null; then
|
|
"$cmd"
|
|
else
|
|
echo "Unknown command: $cmd"
|
|
help
|
|
exit 1
|
|
fi
|
|
done
|
|
elif declare -f "$1" > /dev/null; then
|
|
activate-venv
|
|
"$1" "${@:2}"
|
|
else
|
|
case "$1" in
|
|
*)
|
|
echo "Unknown command: $1"
|
|
help
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|