Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ On remote server where applications will be deployed:
```bash
uv tool install odoo-venv
uv tool install odoo-addons-path
uv tool install click-odoo-contrib
uv tool install git-aggregator
```

Sample configuration file:
Expand Down
13 changes: 7 additions & 6 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ deploy [--config FILE] configure <instance_name> [<ssh_host>] [<repo_url>] [--ty

- Unit file destination: `~/.config/systemd/user/<instance_name>.service`
- Template variables per type:
- **`odoo`**: `instance_name`, `instance_path`, `venv_path`, `addons_path`
- **`odoo`**: `instance_name`, `instance_path`, `venv_path`, `odoo_addons_path`
- **`python`**: `instance_name`, `instance_path`, `venv_path`, `exec_start`
- **`service`**: `instance_name`, `instance_path`, `exec_start`
- After writing the unit file, run:
Expand Down Expand Up @@ -354,7 +354,7 @@ odoo-myproject-production:
db: myproject # Odoo only; defaults to instance_name if omitted

# service / python only
exec_start: myapp.main:app # module path for python; verbatim for service
exec_start: python -m myapp.main:app # `python -m module path` or `python file.py` or `fastapi entry` for python; verbatim for service
build: npm ci && npm run build # service only

# Hooks (update command)
Expand Down Expand Up @@ -395,9 +395,9 @@ After=network.target postgresql.service
[Service]
Type=simple
WorkingDirectory={{ instance_path }}
ExecStart={{ venv_path }}/bin/python {{ instance_path }}/odoo-bin \
ExecStart={{ venv_path }}/bin/python {{ venv_path }}/bin/odoo \
--config {{ instance_path }}/config/odoo.conf \
--addons-path {{ addons_path }}
--addons-path $({{ odoo_addons_path }} {{ instance_path }})
Restart=on-failure
RestartSec=5s

Expand All @@ -415,7 +415,7 @@ After=network.target
[Service]
Type=simple
WorkingDirectory={{ instance_path }}
ExecStart={{ venv_path }}/bin/python -m {{ exec_start }}
ExecStart={{ venv_path }}/bin/{{ exec_start }}
Restart=on-failure
RestartSec=5s

Expand Down Expand Up @@ -503,7 +503,8 @@ The following tools must be pre-installed on the target host:
| `odoo-venv` | `odoo` deployments |
| `odoo-addons-path`| `odoo` deployments |
| `uv` | `python` deployments |
| `click-odoo-upgrade` | `odoo` venv (not a local dep of `deploy`) |
| `click-odoo-contrib` | `odoo` venv (not a local dep of `deploy`) |
| `git-aggregator` | `odoo` deployments |

For `service` deployments, any additional runtime or toolchain (Node.js, Ruby, Rust, etc.) must
also be pre-installed; `deploy` only orchestrates `git pull`, the `build` command, and systemd
Expand Down
24 changes: 15 additions & 9 deletions deploy/command/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import click

from deploy.utils.addons import get_addons_path
from deploy.utils.config import load_config, resolve_options
from deploy.utils.executor import Executor, ExecutorError
from deploy.utils.render import render_unit
Expand Down Expand Up @@ -79,7 +78,8 @@ def configure( # noqa: C901
raise click.ClickException(msg)

executor = Executor(eff_ssh_host, ctx.obj["verbose"], ssh_port=eff_ssh_port)
instance_path = f"$HOME/{instance_name}"
home_dir = executor.capture("echo $HOME")
instance_path = f"{home_dir}/{instance_name}"

# Step 2: Clone repository
if _is_git_repo(executor, instance_path):
Expand All @@ -94,14 +94,16 @@ def configure( # noqa: C901
except ExecutorError as exc:
msg = f"Git clone failed: {exc}"
raise click.ClickException(msg) from exc
executor.run(
"if [ -f addons/repos.yaml ]; then cd addons/ && gitaggregate -c repos.yaml; fi",
cwd=instance_path,
)

# Step 3: Set up environment
click.echo(f"Setting up {eff_type} environment …")
addons_path: str | None = None
try:
if eff_type == "odoo":
setup_odoo_venv(executor, instance_path)
addons_path = get_addons_path(executor, instance_path)
elif eff_type == "python":
setup_python_venv(executor, instance_path, force=force)
else: # service
Expand All @@ -116,19 +118,23 @@ def configure( # noqa: C901
# Step 4: Install systemd unit
click.echo("Installing systemd unit …")
venv_path = f"{instance_path}/.venv"
exec_start: str = opts.get("exec_start", "")

template_vars: dict[str, Any] = {
"instance_name": instance_name,
"instance_path": instance_path,
}
if eff_type == "odoo":
template_vars["venv_path"] = venv_path
template_vars["addons_path"] = addons_path
elif eff_type == "python":
template_vars["venv_path"] = venv_path
template_vars["exec_start"] = exec_start
odoo_addons_path = executor.capture("which odoo-addons-path")
template_vars["odoo_addons_path"] = odoo_addons_path
else:
exec_start: str = opts.get("exec_start", "")
if not exec_start:
msg = "exec_start is required for service or python type."
msg += " Set it in deploy.yml."
raise click.ClickException(msg)
if eff_type == "python":
template_vars["venv_path"] = venv_path
template_vars["exec_start"] = exec_start

try:
Expand Down
6 changes: 4 additions & 2 deletions deploy/command/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def update( # noqa: C901
hooks: dict = opts.get("hooks", {})

executor = Executor(eff_ssh_host, ctx.obj["verbose"], ssh_port=eff_ssh_port)
instance_path = f"$HOME/{instance_name}"
home_dir = executor.capture("echo $HOME")
instance_path = f"{home_dir}/{instance_name}"

def run_hooks(hook_name: str) -> bool:
"""Execute all commands for *hook_name*. Returns True if all succeeded."""
Expand Down Expand Up @@ -116,9 +117,10 @@ def run_hooks(hook_name: str) -> bool:
try:
if eff_type == "odoo":
executor.run(
"if [ -e requirements.txt ]; then uv pip install -r requirements.txt; fi",
"if [ -f addons/repos.yaml ]; then cd addons/ && gitaggregate -c repos.yaml; fi",
cwd=instance_path,
)
executor.run("odoo-venv update .venv --backup", cwd=instance_path)
elif eff_type == "python":
setup_python_deps(executor, instance_path)
else: # service
Expand Down
4 changes: 2 additions & 2 deletions deploy/templates/odoo.service.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ After=network.target postgresql.service
[Service]
Type=simple
WorkingDirectory={{ instance_path }}
ExecStart={{ venv_path }}/bin/python {{ instance_path }}/odoo-bin \
ExecStart={{ venv_path }}/bin/python {{ venv_path }}/bin/odoo \
--config {{ instance_path }}/config/odoo.conf \
--addons-path {{ addons_path }}
--addons-path $({{ odoo_addons_path }} {{ instance_path }})
Restart=on-failure
RestartSec=5s

Expand Down
2 changes: 1 addition & 1 deletion deploy/templates/python.service.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ After=network.target
[Service]
Type=simple
WorkingDirectory={{ instance_path }}
ExecStart={{ venv_path }}/bin/python -m {{ exec_start }}
ExecStart={{ venv_path }}/bin/{{ exec_start }}
Restart=on-failure
RestartSec=5s

Expand Down
3 changes: 1 addition & 2 deletions deploy/utils/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
def setup_odoo_venv(executor: Executor, instance_path: str) -> None:
"""Create or update an Odoo virtual environment using ``odoo-venv``."""
executor.run(
f"odoo-venv create --project-dir {instance_path}",
f"odoo-venv create --project-dir {instance_path} --preset project",
cwd=instance_path,
)
executor.run("uv pip install click-odoo-contrib", cwd=instance_path)


def setup_python_venv(executor: Executor, instance_path: str, force: bool = False) -> None:
Expand Down
Loading