odoo-dev 0.4.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. odoo_dev-1.1.0/.release-please-manifest.json +3 -0
  2. odoo_dev-1.1.0/CHANGELOG.md +26 -0
  3. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/PKG-INFO +11 -10
  4. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/README.md +10 -9
  5. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/pyproject.toml +1 -1
  6. odoo_dev-1.1.0/src/odoo_dev/__init__.py +3 -0
  7. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/cli.py +4 -0
  8. odoo_dev-1.1.0/src/odoo_dev/commands/bump.py +88 -0
  9. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/commands/setup.py +4 -1
  10. odoo_dev-1.1.0/src/odoo_dev/utils/manifest.py +81 -0
  11. odoo_dev-1.1.0/tests/test_bump.py +61 -0
  12. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_cli.py +5 -0
  13. odoo_dev-0.4.0/.release-please-manifest.json +0 -3
  14. odoo_dev-0.4.0/CHANGELOG.md +0 -8
  15. odoo_dev-0.4.0/src/odoo_dev/__init__.py +0 -3
  16. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/.github/workflows/release-please.yml +0 -0
  17. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/.gitignore +0 -0
  18. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/.gitmodules +0 -0
  19. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/.python-version +0 -0
  20. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/release-please-config.json +0 -0
  21. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/commands/__init__.py +0 -0
  22. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/commands/db.py +0 -0
  23. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/commands/docker.py +0 -0
  24. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/commands/run.py +0 -0
  25. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/config.py +0 -0
  26. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/preflight.py +0 -0
  27. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/__init__.py +0 -0
  28. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/docker/Dockerfile +0 -0
  29. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/docker/__init__.py +0 -0
  30. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/docker/docker-entrypoint.sh +0 -0
  31. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/vscode/__init__.py +0 -0
  32. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/vscode/launch.json +0 -0
  33. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/vscode/settings.json +0 -0
  34. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/templates/vscode/tasks.json +0 -0
  35. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/utils/__init__.py +0 -0
  36. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/src/odoo_dev/utils/console.py +0 -0
  37. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/__init__.py +0 -0
  38. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/fixtures/__init__.py +0 -0
  39. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_config.py +0 -0
  40. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_db.py +0 -0
  41. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_db_config.py +0 -0
  42. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_drop_database.py +0 -0
  43. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_integration.py +0 -0
  44. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_preflight.py +0 -0
  45. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_run.py +0 -0
  46. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_setup.py +0 -0
  47. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/tests/test_setup_db.py +0 -0
  48. {odoo_dev-0.4.0 → odoo_dev-1.1.0}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "1.1.0"
3
+ }
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ ## [1.1.0](https://github.com/bemade/odoo-dev/compare/v1.0.0...v1.1.0) (2026-06-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * add `bump` command for series-agnostic manifest version bumps ([#7](https://github.com/bemade/odoo-dev/issues/7)) ([992c8aa](https://github.com/bemade/odoo-dev/commit/992c8aa3731d262803a6f329209275462d88d80a))
9
+
10
+ ## [1.0.0](https://github.com/bemade/odoo-dev/compare/v0.4.0...v1.0.0) (2026-06-11)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * macOS `setup` no longer installs PostgreSQL. Fresh macOS setups must install a server themselves (or point DB_HOST/DB_PORT at a remote/Docker server).
16
+
17
+ ### Features
18
+
19
+ * treat PostgreSQL as an external prerequisite on all platforms ([#5](https://github.com/bemade/odoo-dev/issues/5)) ([e817107](https://github.com/bemade/odoo-dev/commit/e817107ac434a5b23dd2675d59a95d1a6f8d1e71))
20
+
21
+ ## [0.4.0](https://github.com/bemade/odoo-dev/compare/v0.3.3...v0.4.0) (2026-06-11)
22
+
23
+
24
+ ### Features
25
+
26
+ * configurable DB connection + connectivity preflight ([#3](https://github.com/bemade/odoo-dev/issues/3)) ([632738e](https://github.com/bemade/odoo-dev/commit/632738e37c1d22d79ec4a03cba72a28ca580f7c8))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: odoo-dev
3
- Version: 0.4.0
3
+ Version: 1.1.0
4
4
  Summary: Odoo Development Environment Helper
5
5
  Project-URL: Homepage, https://git.bemade.org/bemade/odoo-dev
6
6
  Project-URL: Repository, https://git.bemade.org/bemade/odoo-dev
@@ -55,25 +55,26 @@ Docker at the end — answer "no" if you only want the local venv workflow.
55
55
  ## Database setup (read this before your first `run`/`test`)
56
56
 
57
57
  The generated `conf/odoo.conf` connects as PostgreSQL user **`odoo`** over the local
58
- socket. You need a running PostgreSQL server and a matching role. `setup` never creates
59
- the role, and what it installs differs by OS on **macOS** it installs the server (but
60
- does **not** start it); on **Linux** it installs only the PostgreSQL *client* (so you
61
- supply the server yourself). On a fresh machine do this once:
58
+ socket. **A running PostgreSQL server is a prerequisite you provide yourself** — on
59
+ every platform. `setup` installs only the PostgreSQL *client* and build dependencies
60
+ (macOS: `libpq`; Linux: `postgresql-client` + `libpq-dev`); it never installs, starts,
61
+ or configures a server, and never creates the `odoo` role. So on a fresh machine,
62
+ install a server, start it, and create the role once:
62
63
 
63
64
  **macOS (Homebrew):**
64
65
 
65
66
  ```bash
66
- brew services start postgresql@18 # start the server (use your installed version)
67
- createuser -s odoo # create the role odoo.conf expects
67
+ brew install postgresql@18 # install a server (pick your version)
68
+ brew services start postgresql@18 # start it
69
+ createuser -s odoo # create the role odoo.conf expects
68
70
  # Homebrew's versioned postgres is keg-only; add its bin to PATH if psql/createuser aren't found:
69
71
  # export PATH="$(brew --prefix postgresql@18)/bin:$PATH"
70
72
  ```
71
73
 
72
- **Debian/Ubuntu:** install a server if you don't already have one (or point
73
- `conf/odoo.conf` at an existing / remote / Docker PostgreSQL):
74
+ **Debian/Ubuntu:**
74
75
 
75
76
  ```bash
76
- sudo apt-get install postgresql # if you don't already have a server
77
+ sudo apt-get install postgresql # install a server if you don't already have one
77
78
  sudo systemctl start postgresql
78
79
  sudo -u postgres createuser -s odoo
79
80
  ```
@@ -41,25 +41,26 @@ Docker at the end — answer "no" if you only want the local venv workflow.
41
41
  ## Database setup (read this before your first `run`/`test`)
42
42
 
43
43
  The generated `conf/odoo.conf` connects as PostgreSQL user **`odoo`** over the local
44
- socket. You need a running PostgreSQL server and a matching role. `setup` never creates
45
- the role, and what it installs differs by OS on **macOS** it installs the server (but
46
- does **not** start it); on **Linux** it installs only the PostgreSQL *client* (so you
47
- supply the server yourself). On a fresh machine do this once:
44
+ socket. **A running PostgreSQL server is a prerequisite you provide yourself** — on
45
+ every platform. `setup` installs only the PostgreSQL *client* and build dependencies
46
+ (macOS: `libpq`; Linux: `postgresql-client` + `libpq-dev`); it never installs, starts,
47
+ or configures a server, and never creates the `odoo` role. So on a fresh machine,
48
+ install a server, start it, and create the role once:
48
49
 
49
50
  **macOS (Homebrew):**
50
51
 
51
52
  ```bash
52
- brew services start postgresql@18 # start the server (use your installed version)
53
- createuser -s odoo # create the role odoo.conf expects
53
+ brew install postgresql@18 # install a server (pick your version)
54
+ brew services start postgresql@18 # start it
55
+ createuser -s odoo # create the role odoo.conf expects
54
56
  # Homebrew's versioned postgres is keg-only; add its bin to PATH if psql/createuser aren't found:
55
57
  # export PATH="$(brew --prefix postgresql@18)/bin:$PATH"
56
58
  ```
57
59
 
58
- **Debian/Ubuntu:** install a server if you don't already have one (or point
59
- `conf/odoo.conf` at an existing / remote / Docker PostgreSQL):
60
+ **Debian/Ubuntu:**
60
61
 
61
62
  ```bash
62
- sudo apt-get install postgresql # if you don't already have a server
63
+ sudo apt-get install postgresql # install a server if you don't already have one
63
64
  sudo systemctl start postgresql
64
65
  sudo -u postgres createuser -s odoo
65
66
  ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "odoo-dev"
3
- version = "0.4.0"
3
+ version = "1.1.0"
4
4
  description = "Odoo Development Environment Helper"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -0,0 +1,3 @@
1
+ """Odoo Development Environment Helper."""
2
+
3
+ __version__ = "1.1.0" # x-release-please-version
@@ -5,6 +5,7 @@ from typing import Optional
5
5
  import typer
6
6
 
7
7
  from odoo_dev import __version__
8
+ from odoo_dev.commands import bump as bump_cmd
8
9
  from odoo_dev.commands import db, docker, run, setup
9
10
 
10
11
 
@@ -52,6 +53,9 @@ app.command()(run.update)
52
53
  app.command()(run.test)
53
54
  app.command()(run.scaffold)
54
55
 
56
+ # Versioning
57
+ app.command()(bump_cmd.bump)
58
+
55
59
 
56
60
  def main() -> None:
57
61
  """Entry point for the CLI."""
@@ -0,0 +1,88 @@
1
+ """Bump an Odoo module's manifest version."""
2
+
3
+ import subprocess
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from odoo_dev.config import load_config
10
+ from odoo_dev.utils.console import error, info, success
11
+ from odoo_dev.utils.manifest import (
12
+ bump_version_string,
13
+ find_module_root,
14
+ manifest_path,
15
+ read_version,
16
+ set_version,
17
+ )
18
+
19
+
20
+ def bump(
21
+ module: Annotated[
22
+ str,
23
+ typer.Argument(help="Module name (under addons/) or path to a module dir"),
24
+ ],
25
+ level: Annotated[
26
+ str, typer.Argument(help="Bump level: patch | minor | major")
27
+ ] = "patch",
28
+ no_stage: Annotated[
29
+ bool, typer.Option("--no-stage", help="Do not git add the changed manifest")
30
+ ] = False,
31
+ ) -> None:
32
+ """Bump a module's __manifest__.py version (patch | minor | major).
33
+
34
+ Series-agnostic: only the trailing major.minor.patch segments move, never the
35
+ Odoo series prefix. Edits the manifest in place and stages it, so the bump
36
+ lands in the commit you're about to make (which the version-bump check
37
+ requires for any module you've changed).
38
+ """
39
+ if level not in ("patch", "minor", "major"):
40
+ error(f"level must be one of patch|minor|major (got {level!r})")
41
+ raise typer.Exit(2)
42
+
43
+ # Resolve the module: an explicit path, else a name under addons/.
44
+ candidate = Path(module)
45
+ root = find_module_root(candidate) if candidate.exists() else None
46
+ if root is None and candidate.is_dir():
47
+ root = candidate
48
+ if root is None:
49
+ cfg = load_config()
50
+ under_addons = cfg.addons_dir / module
51
+ if under_addons.exists():
52
+ root = under_addons
53
+ else:
54
+ error(
55
+ f"No module found for {module!r} "
56
+ f"(checked the path and {cfg.addons_dir}/{module})"
57
+ )
58
+ raise typer.Exit(1)
59
+
60
+ mf = manifest_path(root)
61
+ if mf is None:
62
+ error(f"No __manifest__.py in {root}")
63
+ raise typer.Exit(1)
64
+
65
+ # Resolve through any addons/ -> .repos/ symlink so we edit and stage the
66
+ # real file in whichever repo (parent or submodule) actually owns it.
67
+ real_mf = mf.resolve()
68
+ text = real_mf.read_text()
69
+ current = read_version(text)
70
+ if current is None:
71
+ error(f"No version string in {real_mf}")
72
+ raise typer.Exit(1)
73
+
74
+ try:
75
+ new_version = bump_version_string(current, level)
76
+ except ValueError as exc:
77
+ error(str(exc))
78
+ raise typer.Exit(1)
79
+
80
+ real_mf.write_text(set_version(text, new_version))
81
+ success(f"{root.name}: {current} -> {new_version}")
82
+
83
+ if not no_stage:
84
+ result = subprocess.run(
85
+ ["git", "add", real_mf.name], cwd=real_mf.parent, check=False
86
+ )
87
+ if result.returncode != 0:
88
+ info(f"(could not git add {real_mf}; stage it yourself)")
@@ -493,11 +493,14 @@ def _install_system_dependencies() -> None:
493
493
 
494
494
  if system == "Darwin":
495
495
  success("Installing dependencies for macOS...")
496
+ # PostgreSQL is a prerequisite you provide yourself (see the README's
497
+ # "Database setup" section) — we install only the client library and
498
+ # build deps, never the server. `libpq` is keg-only but ships psql /
499
+ # createuser, which is all the client side needs.
496
500
  subprocess.run(
497
501
  [
498
502
  "brew",
499
503
  "install",
500
- "postgresql",
501
504
  "libpq",
502
505
  "openssl",
503
506
  "libxml2",
@@ -0,0 +1,81 @@
1
+ """Read and bump the version string in an Odoo module's ``__manifest__.py``.
2
+
3
+ The version is treated **series-agnostically**: only the trailing
4
+ ``major.minor.patch`` segments move, never the Odoo series prefix (e.g. the
5
+ ``19.0`` in ``19.0.1.2.3``). patch -> last segment, minor -> second-to-last,
6
+ major -> third-to-last (zeroing everything after). A minor/major bump needs
7
+ >=3 segments so the series prefix is never touched.
8
+
9
+ NB: this logic is mirrored in the ``bemade/pre-commit-hooks`` repo
10
+ (``bemade_pre_commit_hooks/_manifest.py``), which enforces the bump in
11
+ pre-commit/CI. Keep the two in sync until they share a published dependency.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import ast
17
+ import re
18
+ from pathlib import Path
19
+ from typing import Optional
20
+
21
+ MANIFEST_NAMES = ("__manifest__.py", "__openerp__.py")
22
+ _VERSION_RE = re.compile(
23
+ r"""(?P<prefix>["']version["']\s*:\s*)(?P<q>["'])(?P<ver>[^"']*)(?P=q)"""
24
+ )
25
+ _LEVEL_INDEX = {"patch": -1, "minor": -2, "major": -3}
26
+
27
+
28
+ def find_module_root(path: Path) -> Optional[Path]:
29
+ for parent in [path, *path.parents]:
30
+ if parent.is_dir() and any((parent / m).is_file() for m in MANIFEST_NAMES):
31
+ return parent
32
+ return None
33
+
34
+
35
+ def manifest_path(module_root: Path) -> Optional[Path]:
36
+ for name in MANIFEST_NAMES:
37
+ p = module_root / name
38
+ if p.is_file():
39
+ return p
40
+ return None
41
+
42
+
43
+ def read_version(manifest_text: str) -> Optional[str]:
44
+ m = _VERSION_RE.search(manifest_text)
45
+ if m:
46
+ return m.group("ver")
47
+ try:
48
+ data = ast.literal_eval(manifest_text.strip())
49
+ if isinstance(data, dict) and isinstance(data.get("version"), str):
50
+ return data["version"]
51
+ except Exception:
52
+ pass
53
+ return None
54
+
55
+
56
+ def set_version(manifest_text: str, new_version: str) -> str:
57
+ def _sub(m: re.Match) -> str:
58
+ return f"{m.group('prefix')}{m.group('q')}{new_version}{m.group('q')}"
59
+
60
+ return _VERSION_RE.sub(_sub, manifest_text, count=1)
61
+
62
+
63
+ def bump_version_string(version: str, level: str) -> str:
64
+ idx = _LEVEL_INDEX.get(level)
65
+ if idx is None:
66
+ raise ValueError(f"unknown bump level {level!r} (patch|minor|major)")
67
+ parts = version.split(".")
68
+ if len(parts) < -idx:
69
+ raise ValueError(f"version {version!r} has too few segments for a {level} bump")
70
+ if level in ("minor", "major") and len(parts) < 3:
71
+ raise ValueError(
72
+ f"refusing a {level} bump on {version!r}: need >=3 segments so the "
73
+ f"series prefix is never touched"
74
+ )
75
+ try:
76
+ parts[idx] = str(int(parts[idx]) + 1)
77
+ except ValueError as exc:
78
+ raise ValueError(f"non-numeric segment in version {version!r}") from exc
79
+ for i in range(idx + 1, 0):
80
+ parts[i] = "0"
81
+ return ".".join(parts)
@@ -0,0 +1,61 @@
1
+ """Tests for the `bump` command and its manifest helpers."""
2
+
3
+ import subprocess
4
+ from pathlib import Path
5
+
6
+ import pytest
7
+ from typer.testing import CliRunner
8
+
9
+ from odoo_dev.cli import app
10
+ from odoo_dev.utils.manifest import bump_version_string, read_version, set_version
11
+
12
+ runner = CliRunner()
13
+
14
+
15
+ @pytest.mark.parametrize(
16
+ "version,level,expected",
17
+ [
18
+ ("19.0.1.2.3", "patch", "19.0.1.2.4"),
19
+ ("19.0.1.2.3", "minor", "19.0.1.3.0"),
20
+ ("19.0.1.2.3", "major", "19.0.2.0.0"),
21
+ ("1.0.0", "patch", "1.0.1"),
22
+ ("1.2.3", "minor", "1.3.0"),
23
+ ("1.2.3", "major", "2.0.0"),
24
+ ],
25
+ )
26
+ def test_bump_version_string(version, level, expected):
27
+ assert bump_version_string(version, level) == expected
28
+
29
+
30
+ def test_minor_needs_three_segments():
31
+ with pytest.raises(ValueError):
32
+ bump_version_string("19.0", "minor")
33
+
34
+
35
+ def test_read_set_roundtrip():
36
+ text = "{\n 'name': 'Foo',\n 'version': '19.0.1.0.0',\n}\n"
37
+ assert read_version(text) == "19.0.1.0.0"
38
+ assert read_version(set_version(text, "19.0.1.0.1")) == "19.0.1.0.1"
39
+
40
+
41
+ def _make_module(tmp_path: Path, version: str) -> Path:
42
+ subprocess.run(["git", "init", "-q"], cwd=tmp_path, check=True)
43
+ mod = tmp_path / "addons" / "acme"
44
+ mod.mkdir(parents=True)
45
+ (mod / "__manifest__.py").write_text(
46
+ "{\n 'name': 'Acme',\n 'version': '%s',\n}\n" % version
47
+ )
48
+ return mod
49
+
50
+
51
+ def test_bump_command_patch(tmp_path):
52
+ mod = _make_module(tmp_path, "19.0.1.0.0")
53
+ result = runner.invoke(app, ["bump", str(mod)])
54
+ assert result.exit_code == 0
55
+ assert read_version((mod / "__manifest__.py").read_text()) == "19.0.1.0.1"
56
+
57
+
58
+ def test_bump_command_rejects_bad_level(tmp_path):
59
+ mod = _make_module(tmp_path, "19.0.1.0.0")
60
+ result = runner.invoke(app, ["bump", str(mod), "nonsense"])
61
+ assert result.exit_code != 0
@@ -51,6 +51,11 @@ class TestCliHelp:
51
51
  result = runner.invoke(app, ["scaffold", "--help"])
52
52
  assert result.exit_code == 0
53
53
 
54
+ def test_bump_help(self):
55
+ result = runner.invoke(app, ["bump", "--help"])
56
+ assert result.exit_code == 0
57
+ assert "patch" in result.output
58
+
54
59
  def test_setup_help(self):
55
60
  result = runner.invoke(app, ["setup", "--help"])
56
61
  assert result.exit_code == 0
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.4.0"
3
- }
@@ -1,8 +0,0 @@
1
- # Changelog
2
-
3
- ## [0.4.0](https://github.com/bemade/odoo-dev/compare/v0.3.3...v0.4.0) (2026-06-11)
4
-
5
-
6
- ### Features
7
-
8
- * configurable DB connection + connectivity preflight ([#3](https://github.com/bemade/odoo-dev/issues/3)) ([632738e](https://github.com/bemade/odoo-dev/commit/632738e37c1d22d79ec4a03cba72a28ca580f7c8))
@@ -1,3 +0,0 @@
1
- """Odoo Development Environment Helper."""
2
-
3
- __version__ = "0.4.0" # x-release-please-version
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes