From e21bb3d567ab3390d9b7b5358702856a7f244e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Wed, 21 Aug 2024 12:21:05 +0300 Subject: [PATCH 01/51] Added new command 'odood odoo run' that allows to run Odoo as command, passing all arguments after '--' to then Odoo binary --- CHANGELOG.md | 9 ++++++++- subpackages/cli/source/odood/cli/commands/odoo.d | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 083818fd..3b9ef34b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Release 0.1.1 (unreleased) + +### Added + +- New commaand `odood odoo run` that allows to run Odoo itself. + +--- + ## Release 0.1.0 (2024-08-15) ### Added @@ -13,7 +21,6 @@ - New command `odood venv run` that allows to run any command from current venv. - New command `odood repo run-pre-commit` to run [pre-commit](https://pre-commit.com/) for the repo. - ### Changed - Database restoration reimplemented in D, diff --git a/subpackages/cli/source/odood/cli/commands/odoo.d b/subpackages/cli/source/odood/cli/commands/odoo.d index a136faa4..acb9a9d3 100644 --- a/subpackages/cli/source/odood/cli/commands/odoo.d +++ b/subpackages/cli/source/odood/cli/commands/odoo.d @@ -27,10 +27,25 @@ class CommandOdooShell: OdoodCommand { } +class CommandOdooRun: OdoodCommand { + this() { + super("run", "Run Odoo. All arguments after '--' will be passed to Odoo."); + } + + public override void execute(ProgramArgs args) { + Project.loadProject.server.getServerRunner() + .addArgs(args.argsRest) + .execv; + } +} + + + class CommandOdoo: OdoodCommand { this() { super("odoo", "Odoo-related utility commands."); this.add(new CommandOdooShell()); + this.add(new CommandOdooRun()); } } From ff217b59ac81029277a969476ec7829c7893dbb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Wed, 21 Aug 2024 12:24:24 +0300 Subject: [PATCH 02/51] Bump commandr version to 1.1.0 --- dub.selections.json | 2 +- subpackages/cli/dub.sdl | 4 ++-- subpackages/cli/dub.selections.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dub.selections.json b/dub.selections.json index f337765d..0b3230da 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -5,7 +5,7 @@ "bindbc-loader": "1.1.5", "cachetools": "0.3.1", "colored": "0.0.31", - "commandr": {"version":"~master","repository":"git+https://github.com/katyukha/commandr.git"}, + "commandr": "1.1.0", "dini": "2.0.0", "dpq": "0.11.6", "dshould": "1.7.2", diff --git a/subpackages/cli/dub.sdl b/subpackages/cli/dub.sdl index 90b674e3..86c7ffd3 100644 --- a/subpackages/cli/dub.sdl +++ b/subpackages/cli/dub.sdl @@ -5,9 +5,9 @@ copyright "Copyright © 2022-2023, Dmytro Katyukha" license "MPL-2.0" dependency "colored" version=">=0.0.31" dependency "tabletool" version="~>0.5.0" -/*dependency "commandr" version=">=1.0.0"*/ +dependency "commandr" version=">=1.1.0" /*dependency "commandr" path="../../../commandr"*/ -dependency "commandr" repository="git+https://github.com/katyukha/commandr.git" version="~master" +/*dependency "commandr" repository="git+https://github.com/katyukha/commandr.git" version="~master"*/ dependency "odood:lib" path="../../" diff --git a/subpackages/cli/dub.selections.json b/subpackages/cli/dub.selections.json index 7b505da4..6439683f 100644 --- a/subpackages/cli/dub.selections.json +++ b/subpackages/cli/dub.selections.json @@ -5,7 +5,7 @@ "bindbc-loader": "1.1.5", "cachetools": "0.3.1", "colored": "0.0.31", - "commandr": {"version":"~master","repository":"git+https://github.com/katyukha/commandr.git"}, + "commandr": "1.1.0", "dini": "2.0.0", "dpq": "0.11.6", "dshould": "1.7.2", From 220e4594d364937a93a12af227cd6bd68b3d71ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Sun, 25 Aug 2024 18:22:27 +0300 Subject: [PATCH 03/51] Minor fixes --- subpackages/lib/source/odood/lib/install/python.d | 3 +-- subpackages/lib/source/odood/lib/odoo/log.d | 3 +-- subpackages/lib/source/odood/lib/venv.d | 2 +- subpackages/utils/source/odood/utils/git/url.d | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/subpackages/lib/source/odood/lib/install/python.d b/subpackages/lib/source/odood/lib/install/python.d index 9b537d6a..0e1982e7 100644 --- a/subpackages/lib/source/odood/lib/install/python.d +++ b/subpackages/lib/source/odood/lib/install/python.d @@ -7,10 +7,9 @@ private import thepath: Path; private import theprocess: resolveProgram; private import odood.lib.project: Project; -private import odood.lib.venv: PySerie; private import odood.lib.odoo.python; private import odood.utils.odoo.serie: OdooSerie; -private import odood.utils: download, parsePythonVersion; +private import odood.utils: parsePythonVersion; private import odood.utils.versioned: Version; private import odood.exception: OdoodException; diff --git a/subpackages/lib/source/odood/lib/odoo/log.d b/subpackages/lib/source/odood/lib/odoo/log.d index 69f24e00..a26495b1 100644 --- a/subpackages/lib/source/odood/lib/odoo/log.d +++ b/subpackages/lib/source/odood/lib/odoo/log.d @@ -60,8 +60,7 @@ immutable auto RE_LOG_RECORD_DATA = ctRegex!( /// String representation of this message const(string) toString() const { - import std.format: format; - auto msg_truncated = msg.length > 200 ? + immutable auto msg_truncated = msg.length > 200 ? (msg[0..200] ~ "...") : msg[0..$]; return "%s %s %s %s %s %s".format( date, process_id, log_level, db, logger, msg_truncated); diff --git a/subpackages/lib/source/odood/lib/venv.d b/subpackages/lib/source/odood/lib/venv.d index 77c8282e..d742aa43 100644 --- a/subpackages/lib/source/odood/lib/venv.d +++ b/subpackages/lib/source/odood/lib/venv.d @@ -6,6 +6,7 @@ private import std.typecons: Nullable; private import std.exception: enforce; private import std.conv: to; private import std.parallelism: totalCPUs; +private import std.regex: ctRegex, matchFirst; private static import std.process; @@ -247,7 +248,6 @@ const struct VirtualEnv { /// ditto void buildPython(in Version build_version, in bool enable_sqlite=false) { - import std.regex: ctRegex, matchFirst; infof("Building python version %s...", build_version); diff --git a/subpackages/utils/source/odood/utils/git/url.d b/subpackages/utils/source/odood/utils/git/url.d index a7143c90..2805c71e 100644 --- a/subpackages/utils/source/odood/utils/git/url.d +++ b/subpackages/utils/source/odood/utils/git/url.d @@ -12,7 +12,7 @@ private import thepath: Path; private import odood.exception: OdoodException; private import theprocess: Process; - +// TODO: Think about using https://code.dlang.org/packages/urld // TODO: Add parsing of branch name from url /// Regex for parsing git URL private auto immutable RE_GIT_URL = ctRegex!( From 21859dc49bce8e1e658e849d7e2b3e6d18777284 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Fri, 6 Sep 2024 23:15:17 +0300 Subject: [PATCH 04/51] [REF] versioned: added basic validation. move parsing to sep method --- .../utils/source/odood/utils/versioned.d | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/subpackages/utils/source/odood/utils/versioned.d b/subpackages/utils/source/odood/utils/versioned.d index 66d42854..edef968b 100644 --- a/subpackages/utils/source/odood/utils/versioned.d +++ b/subpackages/utils/source/odood/utils/versioned.d @@ -1,6 +1,6 @@ module odood.utils.versioned; -private import std.conv: to, ConvOverflowException; +private import std.conv: to, ConvOverflowException, ConvException; private import std.range: empty, zip; private import std.algorithm.searching: canFind; private import std.string : isNumeric; @@ -32,6 +32,17 @@ private enum VersionPart { } this(in string v) { + try { + parseVersionString(v); + _isValid = true; + } catch (ConvException) { + // Cannot convert one of version parts to uint, + // thus version is not valid + _isValid = false; + } + } + + private pure void parseVersionString(in string v) { // TODO: Add validation // TODO: Add support of 'v' prefix if (v.length == 0) return; @@ -127,7 +138,6 @@ private enum VersionPart { break; } } - _isValid = true; } pure nothrow uint major() const { return _major; } @@ -149,6 +159,7 @@ private enum VersionPart { return result; } + /// unittest { import unit_threaded.assertions; Version("1.2.3").major.should == 1; @@ -233,6 +244,15 @@ private enum VersionPart { Version("12.34.56+build-42").isValid.should == true; } + // Test invalid versions + unittest { + import unit_threaded.assertions; + Version("2s").isValid.should == false; + Version("2.3s").isValid.should == false; + Version("2.3.4s").isValid.should == false; + Version("2.3.4-s").isValid.should == true; + } + pure int opCmp(in Version other) const { // TODO: make it nothrow if (this.major != other.major) From 66608f62f8ef8e0fc39198b829dbff9a9c1fd0ae Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Fri, 6 Sep 2024 23:20:32 +0300 Subject: [PATCH 05/51] [REF] versioned: move pure on struct --- .../utils/source/odood/utils/versioned.d | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/subpackages/utils/source/odood/utils/versioned.d b/subpackages/utils/source/odood/utils/versioned.d index edef968b..53b4f57a 100644 --- a/subpackages/utils/source/odood/utils/versioned.d +++ b/subpackages/utils/source/odood/utils/versioned.d @@ -16,7 +16,7 @@ private enum VersionPart { } -@safe struct Version { +@safe pure struct Version { private uint _major=0; private uint _minor=0; private uint _patch=0; @@ -24,7 +24,7 @@ private enum VersionPart { private string _build; private bool _isValid; - this(in uint major, in uint minor=0, in uint patch=0) { + this(in uint major, in uint minor=0, in uint patch=0) nothrow { _major = major; _minor = minor; _patch = patch; @@ -42,7 +42,7 @@ private enum VersionPart { } } - private pure void parseVersionString(in string v) { + private void parseVersionString(in string v) { // TODO: Add validation // TODO: Add support of 'v' prefix if (v.length == 0) return; @@ -140,16 +140,16 @@ private enum VersionPart { } } - pure nothrow uint major() const { return _major; } - pure nothrow uint minor() const { return _minor; } - pure nothrow uint patch() const { return _patch; } - pure nothrow string prerelease() const { return _prerelease; } - pure nothrow string build() const { return _build; } + nothrow uint major() const { return _major; } + nothrow uint minor() const { return _minor; } + nothrow uint patch() const { return _patch; } + nothrow string prerelease() const { return _prerelease; } + nothrow string build() const { return _build; } - pure nothrow bool isValid() const { return _isValid; } - pure nothrow bool isStable() const { return _prerelease.empty; } + nothrow bool isValid() const { return _isValid; } + nothrow bool isStable() const { return _prerelease.empty; } - pure nothrow string toString() const { + nothrow string toString() const { string result = _major.to!string ~ "." ~ _minor.to!string ~ "." ~ _patch.to!string; if (_prerelease.length > 0) @@ -253,7 +253,7 @@ private enum VersionPart { Version("2.3.4-s").isValid.should == true; } - pure int opCmp(in Version other) const { + int opCmp(in Version other) const { // TODO: make it nothrow if (this.major != other.major) return this.major < other.major ? -1 : 1; @@ -263,7 +263,7 @@ private enum VersionPart { return this.patch < other.patch ? -1 : 1; // Just copypaste from semver lib - int compareSufix(scope const string[] suffix, const string[] anotherSuffix) @safe pure + int compareSufix(scope const string[] suffix, const string[] anotherSuffix) { if (!suffix.empty && anotherSuffix.empty) return -1; @@ -317,7 +317,7 @@ private enum VersionPart { assert(Version("1.0.0-rc.2+build.5") != Version("1.0.0-rc.1+build.5")); } - bool opEquals(in Version other) const pure nothrow { + bool opEquals(in Version other) const nothrow { return this.major == other.major && this.minor == other.minor && this.patch == other.patch && From 962481c10335d8632de4ba3ea98d7e9ec7234b21 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sat, 7 Sep 2024 20:33:46 +0300 Subject: [PATCH 06/51] Update default version of Odoo to install --- subpackages/cli/source/odood/cli/commands/init.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subpackages/cli/source/odood/cli/commands/init.d b/subpackages/cli/source/odood/cli/commands/init.d index 00216646..a9282829 100644 --- a/subpackages/cli/source/odood/cli/commands/init.d +++ b/subpackages/cli/source/odood/cli/commands/init.d @@ -20,7 +20,7 @@ class CommandInit: OdoodCommand { this.add(new Option("i", "install-dir", "Directory to install odoo to") .required()); this.add(new Option("v", "odoo-version", "Version of Odoo to install") - .required().defaultValue("14.0")); + .required().defaultValue("17.0")); this.add(new Option( null, "install-type", "Installation type. Accept values: git, archive. Default: archive.") .defaultValue("archive") From 299b36ad9cea380b1b51a6d42e7c329d52255f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Wed, 11 Sep 2024 15:47:38 +0300 Subject: [PATCH 07/51] [REF] Precommit commands moved under 'odood pre-commit' subcommand --- CHANGELOG.md | 8 ++ subpackages/cli/source/odood/cli/app.d | 7 +- .../cli/source/odood/cli/commands/precommit.d | 85 +++++++++++++++++++ .../source/odood/cli/commands/repository.d | 67 --------------- .../lib/source/odood/lib/addons/repository.d | 73 +++------------- .../lib/source/odood/lib/devtools/package.d | 1 + .../lib/source/odood/lib/devtools/precommit.d | 85 +++++++++++++++++++ subpackages/lib/source/odood/lib/odoo/lodoo.d | 2 + 8 files changed, 198 insertions(+), 130 deletions(-) create mode 100644 subpackages/cli/source/odood/cli/commands/precommit.d create mode 100644 subpackages/lib/source/odood/lib/devtools/package.d create mode 100644 subpackages/lib/source/odood/lib/devtools/precommit.d diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b9ef34b..9af406e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ - New commaand `odood odoo run` that allows to run Odoo itself. +### Changed + +- Pre-commit related commands moved to `pre-commit` subcommand. + Thus, following commands now available to work with pre-commit: + - `odood pre-commit init` + - `odood pre-commit set-up` + - `odood pre-commit run` + --- ## Release 0.1.0 (2024-08-15) diff --git a/subpackages/cli/source/odood/cli/app.d b/subpackages/cli/source/odood/cli/app.d index 15578b0f..fe75e7bf 100644 --- a/subpackages/cli/source/odood/cli/app.d +++ b/subpackages/cli/source/odood/cli/app.d @@ -27,6 +27,7 @@ private import odood.cli.commands.script: CommandScript; private import odood.cli.commands.psql: CommandPSQL; private import odood.cli.commands.info: CommandInfo; private import odood.cli.commands.odoo: CommandOdoo; +private import odood.cli.commands.precommit: CommandPreCommit; /** Class that represents main OdoodProgram @@ -47,9 +48,13 @@ class App: OdoodProgram { this.add(new CommandTest()); this.add(new CommandRepository()); this.add(new CommandVenv()); + this.add(new CommandOdoo()); + + // Dev tools + this.topicGroup("Dev Tools"); this.add(new CommandScript()); this.add(new CommandPSQL()); - this.add(new CommandOdoo()); + this.add(new CommandPreCommit()); // System this.topicGroup("System"); diff --git a/subpackages/cli/source/odood/cli/commands/precommit.d b/subpackages/cli/source/odood/cli/commands/precommit.d new file mode 100644 index 00000000..792b8488 --- /dev/null +++ b/subpackages/cli/source/odood/cli/commands/precommit.d @@ -0,0 +1,85 @@ +module odood.cli.commands.precommit; + +private import commandr: Argument, Option, Flag, ProgramArgs; + +private import thepath: Path; + +private import odood.cli.core: OdoodCommand; +private import odood.lib.project: Project; +private import odood.lib.devtools.precommit: + initPreCommit, + setUpPreCommit; + + +class CommandPreCommitInit: OdoodCommand { + this() { + super("init", "Initialize pre-commit for this repo."); + this.add(new Flag( + "f", "force", + "Enforce initialization. " ~ + "This will rewrite pre-commit configurations.")), + this.add(new Flag( + null, "no-setup", + "Do not set up pre-commit. " ~ + "Could be used if pre-commit already set up.")), + this.add(new Argument( + "path", "Path to repository to initialize pre-commit.").optional()); + } + + public override void execute(ProgramArgs args) { + auto project = Project.loadProject; + + auto repo = project.addons.getRepo( + args.arg("path") ? Path(args.arg("path")) : Path.current); + + repo.initPreCommit(args.flag("force"), !args.flag("no-setup")); + } + +} + +class CommandPreCommitSetUp: OdoodCommand { + this() { + super("set-up", "Set up pre-commit for specified repo."); + this.add(new Argument( + "path", "Path to repository to configure.").optional()); + } + + public override void execute(ProgramArgs args) { + auto project = Project.loadProject; + + auto repo = project.addons.getRepo( + args.arg("path") ? Path(args.arg("path")) : Path.current); + + repo.setUpPreCommit(); + } + +} + + +class CommandPreCommitRun: OdoodCommand { + this() { + super("run", "Run pre-commit for specified repo."); + this.add(new Argument( + "path", "Path to repository to run pre-commit for.").optional()); + } + + public override void execute(ProgramArgs args) { + auto project = Project.loadProject; + auto path = args.arg("path") ? Path(args.arg("path")) : Path.current; + project.venv.runner + .withArgs("pre-commit", "run", "--all-files") + .inWorkDir(path) + .execv(); + } + +} + + +class CommandPreCommit: OdoodCommand { + this() { + super("pre-commit", "Work with pre-commit dev tool."); + this.add(new CommandPreCommitInit()); + this.add(new CommandPreCommitSetUp()); + this.add(new CommandPreCommitRun()); + } +} diff --git a/subpackages/cli/source/odood/cli/commands/repository.d b/subpackages/cli/source/odood/cli/commands/repository.d index df2a5ff4..73831fa3 100644 --- a/subpackages/cli/source/odood/cli/commands/repository.d +++ b/subpackages/cli/source/odood/cli/commands/repository.d @@ -88,78 +88,11 @@ class CommandRepositoryFixVersionConflict: OdoodCommand { } -class CommandRepositoryInitPreCommit: OdoodCommand { - this() { - super("init-pre-commit", "Initialize pre-commit for this repo."); - this.add(new Flag( - "f", "force", - "Enforce initialization. " ~ - "This will rewrite pre-commit configurations.")), - this.add(new Flag( - null, "no-setup", - "Do not set up pre-commit. " ~ - "Could be used if pre-commit already set up.")), - this.add(new Argument( - "path", "Path to repository to initialize pre-commit.").optional()); - } - - public override void execute(ProgramArgs args) { - auto project = Project.loadProject; - - auto repo = project.addons.getRepo( - args.arg("path") ? Path(args.arg("path")) : Path.current); - - repo.initPreCommit(args.flag("force"), !args.flag("no-setup")); - } - -} - -class CommandRepositorySetUpPreCommit: OdoodCommand { - this() { - super("set-up-pre-commit", "Set up pre-commit for specified repo."); - this.add(new Argument( - "path", "Path to repository to configure.").optional()); - } - - public override void execute(ProgramArgs args) { - auto project = Project.loadProject; - - auto repo = project.addons.getRepo( - args.arg("path") ? Path(args.arg("path")) : Path.current); - - repo.setUpPreCommit(); - } - -} - - -class CommandRepositoryRunPreCommit: OdoodCommand { - this() { - super("run-pre-commit", "Run pre-commit for specified repo."); - this.add(new Argument( - "path", "Path to repository to run pre-commit for.").optional()); - } - - public override void execute(ProgramArgs args) { - auto project = Project.loadProject; - auto path = args.arg("path") ? Path(args.arg("path")) : Path.current; - project.venv.runner - .withArgs("pre-commit", "run", "--all-files") - .inWorkDir(path) - .execv(); - } - -} - - class CommandRepository: OdoodCommand { this() { super("repo", "Manage git repositories."); this.add(new CommandRepositoryAdd()); this.add(new CommandRepositoryFixVersionConflict()); - this.add(new CommandRepositoryInitPreCommit()); - this.add(new CommandRepositorySetUpPreCommit()); - this.add(new CommandRepositoryRunPreCommit()); } } diff --git a/subpackages/lib/source/odood/lib/addons/repository.d b/subpackages/lib/source/odood/lib/addons/repository.d index 482f6e5b..457f132e 100644 --- a/subpackages/lib/source/odood/lib/addons/repository.d +++ b/subpackages/lib/source/odood/lib/addons/repository.d @@ -1,28 +1,12 @@ module odood.lib.addons.repository; private import std.logger: warningf, infof; -private import std.exception: enforce; private import thepath: Path; private import odood.lib.project: Project; private import odood.exception: OdoodException; -private import odood.utils.git: GitRepository, parseGitURL, gitClone; -private import theprocess; - -// TODO: may be move pre-commit logic somewhere else? - -// Configuration files for pre-commit for Odoo version 17 -immutable string ODOO_PRE_COMMIT_17_PRECOMMIT = import( - "pre-commit/17.0/pre-commit-config.yaml"); -immutable string ODOO_PRE_COMMIT_17_ESLINT = import( - "pre-commit/17.0/eslintrc.yml"); -immutable string ODOO_PRE_COMMIT_17_FLAKE8 = import( - "pre-commit/17.0/flake8"); -immutable string ODOO_PRE_COMMIT_17_ISORT = import( - "pre-commit/17.0/isort.cfg"); -immutable string ODOO_PRE_COMMIT_17_PYLINT = import( - "pre-commit/17.0/pylintrc"); +private import odood.utils.git: GitRepository; class AddonRepository : GitRepository{ @@ -35,53 +19,18 @@ class AddonRepository : GitRepository{ _project = project; } + /** Return Odood project associated with this addons repository + **/ auto project() const => _project; - /// Check if repository has pre-commit configuration. - bool hasPreCommitConfig() const { - return path.join(".pre-commit-config.yaml").exists; - } - - /// Initialize pre-commit for this repository - void initPreCommit(in bool force=false, in bool setup=true) const { - enforce!OdoodException( - force || !hasPreCommitConfig, - "Cannot init pre-commit. Configuration already exists"); - enforce!OdoodException( - project.odoo.serie == 17, - "This feature is available only for Odoo 17 at the moment!"); - infof("Initializing pre-commit for %s repo!", path); - this.path.join(".pre-commit-config.yaml").writeFile( - ODOO_PRE_COMMIT_17_PRECOMMIT); - this.path.join(".eslintrc.yml").writeFile( - ODOO_PRE_COMMIT_17_ESLINT); - this.path.join(".flake8").writeFile( - ODOO_PRE_COMMIT_17_FLAKE8); - this.path.join(".isort.cfg").writeFile( - ODOO_PRE_COMMIT_17_ISORT); - this.path.join(".pylintrc").writeFile( - ODOO_PRE_COMMIT_17_PYLINT); - - if (setup) - setUpPreCommit(); - } - - /// Setup Precommit if needed - void setUpPreCommit() const { - if (hasPreCommitConfig) { - infof("Setting up pre-commit for %s repo!", path); - _project.venv.installPyPackages("pre-commit"); - _project.venv.runE(["pre-commit", "install"]); - } else { - warningf( - "Cannot set up pre-commit for repository %s, " ~ - "because it does not have pre-commit configuration!", - path); - } - } - - /// Return array of odoo addons, found in this repo. - /// this method searches for addons recursively by default. + /** Scan repository for addons and return array of odoo addons, + * found in this repo. + * This method searches for addons recursively by default. + * + * Params: + * recursive = If set to true, search for addons recursively inside repo. + * Otherwise, scan only the root directory of the repo for addons. + **/ auto addons(in bool recursive=true) const { return project.addons.scan(path, recursive); } diff --git a/subpackages/lib/source/odood/lib/devtools/package.d b/subpackages/lib/source/odood/lib/devtools/package.d new file mode 100644 index 00000000..15a14665 --- /dev/null +++ b/subpackages/lib/source/odood/lib/devtools/package.d @@ -0,0 +1 @@ +module odood.lib.devtools; diff --git a/subpackages/lib/source/odood/lib/devtools/precommit.d b/subpackages/lib/source/odood/lib/devtools/precommit.d new file mode 100644 index 00000000..13179a06 --- /dev/null +++ b/subpackages/lib/source/odood/lib/devtools/precommit.d @@ -0,0 +1,85 @@ +module odood.lib.devtools.precommit; + +private import std.logger: warningf, infof; +private import std.exception: enforce; + +private import odood.lib.addons.repository: AddonRepository; +private import odood.exception: OdoodException; + + +// Configuration files for pre-commit for Odoo version 17 +immutable string ODOO_PRE_COMMIT_17_PRECOMMIT = import( + "pre-commit/17.0/pre-commit-config.yaml"); +immutable string ODOO_PRE_COMMIT_17_ESLINT = import( + "pre-commit/17.0/eslintrc.yml"); +immutable string ODOO_PRE_COMMIT_17_FLAKE8 = import( + "pre-commit/17.0/flake8"); +immutable string ODOO_PRE_COMMIT_17_ISORT = import( + "pre-commit/17.0/isort.cfg"); +immutable string ODOO_PRE_COMMIT_17_PYLINT = import( + "pre-commit/17.0/pylintrc"); + + +/** Check if repository has precommit configuration file + * + * Params: + * repo = repository to check + * + * Returns: + * true if repository has pre-commit config file, otherwise false + **/ +bool hasPreCommitConfig(in AddonRepository repo) { + return repo.path.join(".pre-commit-config.yaml").exists; +} + + +/** Initialize pre-commit for specified repo. + * + * Params: + * repo = repository to initialize pre-commit for. + * force = if set to true, rewrite already existing pre-commit config. + * setup = if set to true, then automatically set up pre-commit according to new configuration. + **/ +void initPreCommit(in AddonRepository repo, in bool force=false, in bool setup=true) { + enforce!OdoodException( + force || !repo.hasPreCommitConfig, + "Cannot init pre-commit. Configuration already exists"); + enforce!OdoodException( + repo.project.odoo.serie == 17, + "This feature is available only for Odoo 17 at the moment!"); + infof("Initializing pre-commit for %s repo!", repo.path); + repo.path.join(".pre-commit-config.yaml").writeFile( + ODOO_PRE_COMMIT_17_PRECOMMIT); + repo.path.join(".eslintrc.yml").writeFile( + ODOO_PRE_COMMIT_17_ESLINT); + repo.path.join(".flake8").writeFile( + ODOO_PRE_COMMIT_17_FLAKE8); + repo.path.join(".isort.cfg").writeFile( + ODOO_PRE_COMMIT_17_ISORT); + repo.path.join(".pylintrc").writeFile( + ODOO_PRE_COMMIT_17_PYLINT); + + if (setup) + setUpPreCommit(repo); +} + + +/** Set up pre-commit for specified repository. + * This means, installing pre-commit in virtualenv of related project, + * and running "pre-commit install" command. + * + * Params: + * repo = repository to initialize pre-commit for. + **/ +void setUpPreCommit(in AddonRepository repo) { + if (repo.hasPreCommitConfig) { + infof("Setting up pre-commit for %s repo!", repo.path); + repo.project.venv.installPyPackages("pre-commit"); + repo.project.venv.runE(["pre-commit", "install"]); + } else { + warningf( + "Cannot set up pre-commit for repository %s, " ~ + "because it does not have pre-commit configuration!", + repo.path); + } +} diff --git a/subpackages/lib/source/odood/lib/odoo/lodoo.d b/subpackages/lib/source/odood/lib/odoo/lodoo.d index 868f74f6..74bb19d0 100644 --- a/subpackages/lib/source/odood/lib/odoo/lodoo.d +++ b/subpackages/lib/source/odood/lib/odoo/lodoo.d @@ -16,6 +16,8 @@ private import odood.utils: generateRandomString; private import odood.utils.odoo.db: BackupFormat; private import odood.exception: OdoodException; +// TODO: Do we need all this for Odoo 17+? It seems that it has built-in commands +// for database management /** Wrapper struct around [LOdoo](https://pypi.org/project/lodoo/) * python CLI util From efc45aff1260af6614bbdc5a77154910305b7aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Wed, 11 Sep 2024 15:50:01 +0300 Subject: [PATCH 08/51] Bump versions --- dub.selections.json | 2 +- subpackages/cli/dub.selections.json | 2 +- subpackages/lib/dub.selections.json | 2 +- subpackages/utils/dub.selections.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dub.selections.json b/dub.selections.json index 0b3230da..5f0cb09e 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -15,7 +15,7 @@ "requests": "2.1.3", "silly": "1.1.1", "tabletool": "0.5.0", - "thepath": "1.2.0", + "thepath": "2.0.0", "theprocess": "0.0.5", "tinyendian": "0.2.0", "unit-threaded": "2.1.9", diff --git a/subpackages/cli/dub.selections.json b/subpackages/cli/dub.selections.json index 6439683f..cdca8ed3 100644 --- a/subpackages/cli/dub.selections.json +++ b/subpackages/cli/dub.selections.json @@ -15,7 +15,7 @@ "prettyprint": "1.0.9", "requests": "2.1.3", "tabletool": "0.5.0", - "thepath": "1.2.0", + "thepath": "2.0.0", "theprocess": "0.0.5", "tinyendian": "0.2.0", "unit-threaded": "2.1.9", diff --git a/subpackages/lib/dub.selections.json b/subpackages/lib/dub.selections.json index 7d18970e..dbfcd00c 100644 --- a/subpackages/lib/dub.selections.json +++ b/subpackages/lib/dub.selections.json @@ -11,7 +11,7 @@ "odood": {"path":"../../"}, "prettyprint": "1.0.9", "requests": "2.1.3", - "thepath": "1.2.0", + "thepath": "2.0.0", "theprocess": "0.0.5", "tinyendian": "0.2.0", "unit-threaded": "2.2.0", diff --git a/subpackages/utils/dub.selections.json b/subpackages/utils/dub.selections.json index 7a872dd3..e1b04101 100644 --- a/subpackages/utils/dub.selections.json +++ b/subpackages/utils/dub.selections.json @@ -8,7 +8,7 @@ "odood": {"path":"../../"}, "prettyprint": "1.0.9", "requests": "2.1.3", - "thepath": "1.2.0", + "thepath": "2.0.0", "theprocess": "0.0.5", "unit-threaded": "2.2.0", "zipper": "0.0.5" From 3168a44655ced31bc9aa6ab1d6f18240bee29b74 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Sep 2024 01:01:24 +0300 Subject: [PATCH 09/51] Initial implementation of 'odood deploy' command --- subpackages/cli/source/odood/cli/app.d | 2 + .../cli/source/odood/cli/commands/deploy.d | 124 ++++++++++++++ .../lib/source/odood/lib/deploy/config.d | 74 +++++++++ .../lib/source/odood/lib/deploy/odoo.d | 154 ++++++++++++++++++ .../lib/source/odood/lib/deploy/package.d | 4 + .../lib/source/odood/lib/deploy/utils.d | 54 ++++++ .../lib/source/odood/lib/project/config.d | 20 +++ .../lib/source/odood/lib/project/project.d | 8 +- .../lib/source/odood/lib/server/server.d | 16 +- 9 files changed, 452 insertions(+), 4 deletions(-) create mode 100644 subpackages/cli/source/odood/cli/commands/deploy.d create mode 100644 subpackages/lib/source/odood/lib/deploy/config.d create mode 100644 subpackages/lib/source/odood/lib/deploy/odoo.d create mode 100644 subpackages/lib/source/odood/lib/deploy/package.d create mode 100644 subpackages/lib/source/odood/lib/deploy/utils.d diff --git a/subpackages/cli/source/odood/cli/app.d b/subpackages/cli/source/odood/cli/app.d index fe75e7bf..48bb9a4f 100644 --- a/subpackages/cli/source/odood/cli/app.d +++ b/subpackages/cli/source/odood/cli/app.d @@ -11,6 +11,7 @@ private import odood.exception: OdoodException; private import odood.cli.core.logger: OdoodLogger; private import odood.cli.core: OdoodProgram, OdoodCommand; private import odood.cli.commands.init: CommandInit; +private import odood.cli.commands.deploy: CommandDeploy; private import odood.cli.commands.server: CommandServer, CommandServerStart, CommandServerStop, CommandServerRestart, CommandServerBrowse, CommandServerLogView; @@ -41,6 +42,7 @@ class App: OdoodProgram { this.summary("Easily manage odoo installations."); this.topicGroup("Main"); this.add(new CommandInit()); + this.add(new CommandDeploy()); this.add(new CommandServer()); this.add(new CommandStatus()); this.add(new CommandDatabase()); diff --git a/subpackages/cli/source/odood/cli/commands/deploy.d b/subpackages/cli/source/odood/cli/commands/deploy.d new file mode 100644 index 00000000..0df1edcb --- /dev/null +++ b/subpackages/cli/source/odood/cli/commands/deploy.d @@ -0,0 +1,124 @@ +module odood.cli.commands.deploy; + +private import core.sys.posix.unistd: geteuid, getegid; + +private import std.logger; +private import std.format: format; +private import std.exception: enforce, errnoEnforce; +private import std.conv: octal; + +private import thepath: Path; +private import theprocess: Process; +private import commandr: Option, Flag, ProgramArgs, acceptsValues; +private import dini: Ini; + +private import odood.cli.core: OdoodCommand, OdoodCLIException; +private import odood.lib.project: + Project, OdooInstallType, ODOOD_SYSTEM_CONFIG_PATH; +private import odood.lib.project.config: ProjectServerSupervisor; +private import odood.lib.odoo.config: initOdooConfig; +private import odood.lib.postgres: createNewPostgresUser; +private import odood.utils.odoo.serie: OdooSerie; +private import odood.utils: generateRandomString; + +private import odood.lib.deploy; + + +class CommandDeploy: OdoodCommand { + this() { + super("deploy", "Deploy production-ready Odoo."); + this.add(new Option("v", "odoo-version", "Version of Odoo to install") + .required().defaultValue("17.0")); + this.add(new Option( + null, "py-version", "Install specific python version.") + .defaultValue("auto")); + this.add(new Option( + null, "node-version", "Install specific node version.") + .defaultValue("lts")); + + this.add(new Option( + null, "db-host", "Database host").defaultValue("localhost")); + this.add(new Option( + null, "db-port", "Database port").defaultValue("False")); + this.add(new Option( + null, "db-user", "Database port").defaultValue("odoo")); + this.add(new Option( + null, "db-password", "Database password").defaultValue("odoo")); + + this.add(new Flag( + null, "proxy-mode", "Enable proxy-mode in odoo config")); + } + + DeployConfig parseDeployOptions(ProgramArgs args) { + DeployConfig config; + config.odoo.serie = OdooSerie(args.option("odoo-version")); + + if (args.option("py-version")) + config.py_version = args.option("py-version"); + if (args.option("node-version")) + config.node_version = args.option("node-version"); + + if (args.option("db-host")) + config.database.host = args.option("db-host"); + if (args.option("db-port")) + config.database.port = args.option("db-port"); + if (args.option("db-user")) + config.database.user = args.option("db-user"); + if (args.option("db-password")) + config.database.password = args.option("db-password"); + + if (args.flag("proxy-mode")) + config.odoo.proxy_mode = true; + return config; + } + + void validateDeploy(ProgramArgs args, in DeployConfig deploy_config) { + // TODO: move to odood.lib.deploy + enforce!OdoodCLIException( + geteuid == 0 && getegid == 0, + "This command must be ran as root!"); + + enforce!OdoodCLIException( + deploy_config.odoo.serie.isValid, + "Odoo version %s is not valid".format(args.option("odoo-version"))); + enforce!OdoodCLIException( + !deploy_config.deploy_path.exists, + "Deploy path %s already exists. ".format(deploy_config.deploy_path) ~ + "It seems that there was attempt to install Odoo. " ~ + "This command can install Odoo only on clean machine."); + enforce!OdoodCLIException( + !ODOOD_SYSTEM_CONFIG_PATH.exists, + "Odood system-wide config already exists at %s. ".format(ODOOD_SYSTEM_CONFIG_PATH) ~ + "It seems that there was attempt to install Odoo. " ~ + "This command can install Odoo only on clean machine."); + enforce!OdoodCLIException( + !Path("etc", "logrotate.d", "odoo").exists, + "It seems that Odoo config for logrotate already exists!"); + enforce!OdoodCLIException( + !Path("etc", "systemd", "system", "odoo.service").exists, + "It seems that systemd service for Odoo already exists!"); + } + + public override void execute(ProgramArgs args) { + // TODO: run only as root + /* Plan: + * 0. Update locales + * 1. Deploy Odoo in /opt/odoo + * 2. Create system user + * 3. Set access rights for Odoo + * 4. Prepare systemd configuration for Odoo + * 5. Install postgres if needed + * 6. Create postgres user if needed + * 7. Configure logrotate + * 8. Install nginx if needed + * 9. Configure Odoo + */ + auto deploy_config = parseDeployOptions(args); + validateDeploy(args, deploy_config); + + auto project = deployOdoo(deploy_config); + } + +} + + diff --git a/subpackages/lib/source/odood/lib/deploy/config.d b/subpackages/lib/source/odood/lib/deploy/config.d new file mode 100644 index 00000000..7d04ef21 --- /dev/null +++ b/subpackages/lib/source/odood/lib/deploy/config.d @@ -0,0 +1,74 @@ +module odood.lib.deploy.config; + +private import std.conv: to; + +private import thepath: Path; + +private import odood.lib.odoo.config: initOdooConfig; +private import odood.lib.project: Project, OdooInstallType; +private import odood.lib.project.config: ProjectServerSupervisor; +private import odood.utils.odoo.serie: OdooSerie; +private import odood.utils: generateRandomString; + +immutable auto DEFAULT_PASSWORD_LEN = 32; + + +struct DeployConfigDatabase { + string host="localhost"; + string port="5432"; + string user="odoo"; + string password; + bool local_postgres=false; +} + +struct DeployConfigOdoo { + OdooSerie serie; + bool proxy_mode=false; + string http_host="localhost"; + string http_port="8069"; + uint workers=0; + + string server_user="odoo"; + ProjectServerSupervisor server_supervisor=ProjectServerSupervisor.Systemd; + +} + +struct DeployConfig { + Path deploy_path = Path("/", "opt", "odoo"); + string py_version="auto"; + string node_version="lts"; + OdooInstallType install_type=OdooInstallType.Archive; + + DeployConfigDatabase database; + DeployConfigOdoo odoo; + + auto prepareOdooConfig(in Project project) const + in ( + project.odoo.serie == this.odoo.serie + ) { + auto odoo_config = initOdooConfig(project); + odoo_config["options"].setKey( + "admin_passwd", generateRandomString(DEFAULT_PASSWORD_LEN)); + + // DB config + odoo_config["options"].setKey("db_host", database.host); + odoo_config["options"].setKey("db_port", database.port); + odoo_config["options"].setKey("db_user", database.user); + odoo_config["options"].setKey("db_password", database.password); + + if (odoo.serie < OdooSerie(11)) { + odoo_config["options"].setKey("xmlrpc_interface", odoo.http_host); + odoo_config["options"].setKey("xmlrpc_port", odoo.http_port); + } else { + odoo_config["options"].setKey("http_interface", odoo.http_host); + odoo_config["options"].setKey("http_port", odoo.http_port); + } + + odoo_config["options"].setKey("workers", odoo.workers.to!string); + + if (odoo.proxy_mode) + odoo_config["options"].setKey("proxy_mode", "True"); + + return odoo_config; + } +} diff --git a/subpackages/lib/source/odood/lib/deploy/odoo.d b/subpackages/lib/source/odood/lib/deploy/odoo.d new file mode 100644 index 00000000..3b70b9e7 --- /dev/null +++ b/subpackages/lib/source/odood/lib/deploy/odoo.d @@ -0,0 +1,154 @@ +module odood.lib.deploy.odoo; + +private import core.sys.posix.unistd: geteuid, getegid; +private import core.sys.posix.pwd: getpwnam, passwd; + +private import std.logger: infof; +private import std.exception: enforce, errnoEnforce; +private import std.conv: text, octal; +private import std.format: format; + +private import thepath: Path; +private import theprocess: Process; + +private import odood.utils.odoo.serie: OdooSerie; +private import odood.lib.project: Project, ODOOD_SYSTEM_CONFIG_PATH; +private import odood.lib.project.config: + ProjectConfigDirectories, ProjectConfigOdoo; + +private import odood.lib.deploy.config: DeployConfig; +private import odood.lib.deploy.utils: checkSystemUserExists, createSystemUser; + + + +private void deploySystemdConfig(in Project project) { + immutable auto odoo_systemd_path = Path( + "etc", "systemd", "system", "odoo.service"); + + infof("Configuring systemd daemon for Odoo..."); + + // Configure systemd + odoo_systemd_path.writeFile( +i"[Unit] +Description=Odoo Open Source ERP and CRM +After=network.target + +[Service] +Type=simple +User=$(project.odoo.server_user) +Group=$(project.odoo.server_user) +ExecStart=%(project.server.scriptPath) --config $(project.odoo.configfile) +KillMode=mixed + +[Install] +WantedBy=multi-user.target +".text); + + // Set access rights for systemd config + odoo_systemd_path.setAttributes(octal!755); + odoo_systemd_path.chown("root", "root"); + + // Enable systemd service for Odoo + Process("systemctl") + .withArgs("daemon-reload") + .execute + .ensureOk(true); + Process("systemctl") + .withArgs("enable", "--now", "odoo.service") + .execute + .ensureOk(true); + Process("systemctl") + .withArgs("start", "odoo.service") + .execute + .ensureOk(true); + + infof("Systemd configred successfully. Odoo will be started at startup."); +} + + +private void deployLogrotateConfig(in Project project) { + immutable auto logrotate_config_path = Path("etc", "logrotate.d", "odoo"); + + infof("Configuring logrotate for Odoo..."); + logrotate_config_path.writeFile( +i"$(project.directories.log.toString)/*.log { + copytruncate + missingok + notifempty +}".text); + + // Set access rights for logrotate config + logrotate_config_path.setAttributes(octal!755); + logrotate_config_path.chown("root", "root"); + + infof("Logrotate configured successfully."); +} + +private void setAccessRights(in Project project) { + import std.string: toStringz; + // Get info about odoo user + auto pw_odoo = getpwnam(project.odoo.server_user.toStringz); + errnoEnforce( + pw_odoo !is null, + "Cannot get info about user %s".format(project.odoo.server_user)); + + // Config is owned by root, but readable by Odoo + project.odoo.configfile.chown(0, pw_odoo.pw_gid); + project.odoo.configfile.setAttributes(octal!640); + + // Odoo can read and write and create files in log directory + project.directories.log.chown(pw_odoo.pw_uid, pw_odoo.pw_gid); + project.directories.log.setAttributes(octal!750); + + // Make Odoo owner of data directory. Do not allow others to access it. + project.directories.data.chown(pw_odoo.pw_uid, pw_odoo.pw_gid); + project.directories.data.setAttributes(octal!750); + + // Make Odoo owner of project root (/opt/odoo), but not recursively, + // thus, Odoo will be able to create files there, + // but will not be allowed to change existing files. + project.project_root.chown(pw_odoo.pw_uid, pw_odoo.pw_gid); +} + +Project deployOdoo(in DeployConfig config) { + infof("Deploying Odoo %s to %s", config.odoo.serie, config.deploy_path); + + auto project_directories = ProjectConfigDirectories(config.deploy_path); + auto project_odoo = ProjectConfigOdoo( + config.deploy_path, project_directories, config.odoo.serie); + project_odoo.server_user = config.odoo.server_user; + project_odoo.server_supervisor = config.odoo.server_supervisor; + + auto project = new Project( + config.deploy_path, + project_directories, + project_odoo); + + auto odoo_config = config.prepareOdooConfig(project); + project.initialize( + odoo_config, + config.py_version, + config.node_version, + config.install_type); + project.save(ODOOD_SYSTEM_CONFIG_PATH); + + if (!checkSystemUserExists(project.odoo.server_user)) + createSystemUser(project.project_root, project.odoo.server_user); + + // Set access rights for Odoo installed + project.setAccessRights(); + + // Configure logrotate + // TODO: make it optional + deployLogrotateConfig(project); + + // Configure systemd + // TODO: make it optional + deploySystemdConfig(project); + + infof("Odoo deployed successfully."); + return project; +} + + + diff --git a/subpackages/lib/source/odood/lib/deploy/package.d b/subpackages/lib/source/odood/lib/deploy/package.d new file mode 100644 index 00000000..35552919 --- /dev/null +++ b/subpackages/lib/source/odood/lib/deploy/package.d @@ -0,0 +1,4 @@ +module odood.lib.deploy; + +public import odood.lib.deploy.config: DeployConfig; +public import odood.lib.deploy.odoo: deployOdoo; diff --git a/subpackages/lib/source/odood/lib/deploy/utils.d b/subpackages/lib/source/odood/lib/deploy/utils.d new file mode 100644 index 00000000..516d48ca --- /dev/null +++ b/subpackages/lib/source/odood/lib/deploy/utils.d @@ -0,0 +1,54 @@ +module odood.lib.deploy.utils; + +private import std.format: format; +private import std.exception: enforce, errnoEnforce; + +private import core.sys.posix.unistd: geteuid, getegid; +private import core.sys.posix.pwd: getpwnam_r, passwd; + +private import theprocess: Process; +private import thepath: Path; + + +bool checkSystemUserExists(in string username) { + import std.string: toStringz; + passwd pwd; + passwd* result; + long bufsize = 16384; + char[] buf = new char[bufsize]; + + int s = getpwnam_r(username.toStringz, &pwd, &buf[0], bufsize, &result); + errnoEnforce( + s == 0, + "Got error on attempt to check if user %s exists".format(username)); + if (result) + return true; + return false; +} + + +void createSystemUser(in Path home, in string name) { + Process("adduser") + .withArgs( + "--system", "--no-create-home", + "--home", home.toString, + "--quiet", + "--group", + name) + .execute() + .ensureOk(true); +} + + +void createPostgresUser(in string username, in string password) { + Process("psql") + .withUser("postgres") + .withArgs( + "psql", "-c", + "CREATE USER \"%s\" WITH CREATEDB PASSWORD '%s'".format( + username, password), + ) + .execute() + .ensureOk(true); +} + diff --git a/subpackages/lib/source/odood/lib/project/config.d b/subpackages/lib/source/odood/lib/project/config.d index 7df5bfc2..87a26dbc 100644 --- a/subpackages/lib/source/odood/lib/project/config.d +++ b/subpackages/lib/source/odood/lib/project/config.d @@ -19,6 +19,9 @@ enum ProjectServerSupervisor { /// Server is managed by init script in /etc/init.d odoo InitScript, + + /// Server is managed by systemd + Systemd, } @@ -80,6 +83,17 @@ struct ProjectConfigOdoo { repo = odoo_repo.empty ? DEFAULT_ODOO_REPO : odoo_repo; } + this(in Path project_root, + in ProjectConfigDirectories directories, + in OdooSerie odoo_serie) { + this( + project_root, + directories, + odoo_serie, + odoo_serie.toString, // Default branch for serie + DEFAULT_ODOO_REPO); + } + this(in dyaml.Node config) { /* TODO: think about following structure of test config in yml: * odoo: @@ -114,6 +128,9 @@ struct ProjectConfigOdoo { case "init-script": this.server_supervisor = ProjectServerSupervisor.InitScript; break; + case "systemd": + this.server_supervisor = ProjectServerSupervisor.Systemd; + break; default: assert( 0, @@ -146,6 +163,9 @@ struct ProjectConfigOdoo { case ProjectServerSupervisor.InitScript: result["server-supervisor"] = "init-script"; break; + case ProjectServerSupervisor.Systemd: + result["server-supervisor"] = "systemd"; + break; } return result; diff --git a/subpackages/lib/source/odood/lib/project/project.d b/subpackages/lib/source/odood/lib/project/project.d index 6639fec3..48d5e19f 100644 --- a/subpackages/lib/source/odood/lib/project/project.d +++ b/subpackages/lib/source/odood/lib/project/project.d @@ -38,6 +38,9 @@ enum OdooInstallType { Git, } +/** Define path for odood system-wide project config + **/ +immutable auto ODOOD_SYSTEM_CONFIG_PATH = Path("/", "etc", "odood.yml"); /** The Odood project. * The main entity to manage whole Odood project @@ -63,8 +66,9 @@ class Project { // If config is not found in current directory and above, // check server-wide config (may be it is installed in server-mode) - if (s_config_path.isNull && Path("/", "etc", "odood.yml").exists) - s_config_path = Path("/", "etc", "odood.yml").nullable; + if (s_config_path.isNull && ODOOD_SYSTEM_CONFIG_PATH.exists) + // We have to copy Path, because nullable does not work on immutable path. + s_config_path = Path(ODOOD_SYSTEM_CONFIG_PATH.toString).nullable; enforce!OdoodException( !s_config_path.isNull, diff --git a/subpackages/lib/source/odood/lib/server/server.d b/subpackages/lib/source/odood/lib/server/server.d index b9e92dd2..eddd54c5 100644 --- a/subpackages/lib/source/odood/lib/server/server.d +++ b/subpackages/lib/source/odood/lib/server/server.d @@ -288,7 +288,13 @@ struct OdooServer { Process("/etc/init.d/odoo") .withArgs("start") .execute - .ensureOk(); + .ensureOk(true); + break; + case ProjectServerSupervisor.Systemd: + Process("service") + .withArgs("odoo", "start") + .execute + .ensureOk(true); break; } if (wait_timeout != Duration.zero) { @@ -350,7 +356,13 @@ struct OdooServer { Process("/etc/init.d/odoo") .withArgs("stop") .execute - .ensureOk(); + .ensureOk(true); + break; + case ProjectServerSupervisor.Systemd: + Process("service") + .withArgs("odoo", "stop") + .execute + .ensureOk(true); break; } } From 84715ca3115f76f7cda40ae23e3e8fb44c2c2596 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Sep 2024 01:11:19 +0300 Subject: [PATCH 10/51] [CI] Added workflow for deployment tests --- .github/workflows/test-deployments.yml | 94 ++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/test-deployments.yml diff --git a/.github/workflows/test-deployments.yml b/.github/workflows/test-deployments.yml new file mode 100644 index 00000000..bdca9fb0 --- /dev/null +++ b/.github/workflows/test-deployments.yml @@ -0,0 +1,94 @@ + +# Workflow to test Odoo deployments on various OS +name: Tests OS deployments +on: + push: + branches: + - '*' +env: + ODOOD_DLANG_COMPILER: ldc-1.39.0 + +# In this test, we build Odood on Ubuntu 20.04 and then try to run +# produced binary on different distros and versions +jobs: + # Compile test builds on ubuntu 20.04 + compile-ubuntu-20_04: + name: Build Ubuntu:20.04 + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + + - name: Install D compiler + uses: dlang-community/setup-dlang@v1 + with: + compiler: ${{ env.ODOOD_DLANG_COMPILER }} + + - name: Install system dependencies + uses: lyricwulf/abc@v1 + with: + linux: libzip-dev libpq-dev python3-dev + + - name: Build Odood + run: | + dub build -b unittest-cov + + - name: Upload Odood compiled assets + uses: actions/upload-artifact@v3 + with: + name: odood-ubuntu-20.04 + path: | + build/odood + + # Run integration tests for different operation systems + run-deployment-tests: + name: Run deployment tests + strategy: + fail-fast: false + matrix: + image: + - "debian:bullseye" + #- "ubuntu:20.04" + #- "ubuntu:22.04" + - "ubuntu:23.04" + - "ubuntu:24.04" + odoo_version: + - "17.0" + #- "16.0" + runs-on: ubuntu-22.04 + needs: + - compile-ubuntu-20_04 + container: + image: ${{ matrix.image }} + env: + DEBIAN_FRONTEND: 'noninteractive' + steps: + - uses: actions/checkout@v3 + + - name: 'Download artifacts for ubuntu 20.04' + uses: actions/download-artifact@v3 + with: + name: odood-ubuntu-20.04 + path: build + + - name: Update apt registry + run: apt-get update + + - name: Install system dependencies + run: apt-get install --no-install-recommends -yq sudo logrotate + + - name: Install package dependencies + run: apt-get install --no-install-recommends -yq $(cat .ci/deps/universal-deb.txt) + + - name: Make test build executable + run: chmod a+x ./build/odood + + - name: Run tests + run: ./build/odood deploy -v ${{ matrix.odoo_version }} + + # TODO: Add test some operations with this instance + + - name: Upload coverage to codecov + uses: codecov/codecov-action@v3 + with: + flags: deployment-tests-${{ matrix.image }}-${{ matrix.odoo_version }} + name: odood-deployment-tests-${{ matrix.image }}-${{ matrix.odoo_version }} From 193ab61e0cc315171f2e57918188da6d392527be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Thu, 12 Sep 2024 11:57:15 +0300 Subject: [PATCH 11/51] [FIX] Deploy logrotate config --- subpackages/lib/source/odood/lib/deploy/odoo.d | 14 ++++++++------ subpackages/lib/source/odood/lib/project/config.d | 11 ++++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/subpackages/lib/source/odood/lib/deploy/odoo.d b/subpackages/lib/source/odood/lib/deploy/odoo.d index 3b70b9e7..d81846f1 100644 --- a/subpackages/lib/source/odood/lib/deploy/odoo.d +++ b/subpackages/lib/source/odood/lib/deploy/odoo.d @@ -20,15 +20,15 @@ private import odood.lib.deploy.config: DeployConfig; private import odood.lib.deploy.utils: checkSystemUserExists, createSystemUser; +immutable auto ODOO_SYSTEMD_PATH = Path( + "/", "etc", "systemd", "system", "odoo.service"); private void deploySystemdConfig(in Project project) { - immutable auto odoo_systemd_path = Path( - "etc", "systemd", "system", "odoo.service"); infof("Configuring systemd daemon for Odoo..."); // Configure systemd - odoo_systemd_path.writeFile( + ODOO_SYSTEMD_PATH.writeFile( i"[Unit] Description=Odoo Open Source ERP and CRM After=network.target @@ -45,8 +45,8 @@ WantedBy=multi-user.target ".text); // Set access rights for systemd config - odoo_systemd_path.setAttributes(octal!755); - odoo_systemd_path.chown("root", "root"); + ODOO_SYSTEMD_PATH.setAttributes(octal!755); + ODOO_SYSTEMD_PATH.chown("root", "root"); // Enable systemd service for Odoo Process("systemctl") @@ -67,7 +67,7 @@ WantedBy=multi-user.target private void deployLogrotateConfig(in Project project) { - immutable auto logrotate_config_path = Path("etc", "logrotate.d", "odoo"); + immutable auto logrotate_config_path = Path("/", "etc", "logrotate.d", "odoo"); infof("Configuring logrotate for Odoo..."); logrotate_config_path.writeFile( @@ -113,11 +113,13 @@ private void setAccessRights(in Project project) { Project deployOdoo(in DeployConfig config) { infof("Deploying Odoo %s to %s", config.odoo.serie, config.deploy_path); + // TODO: Move this configuration to Deploy config auto project_directories = ProjectConfigDirectories(config.deploy_path); auto project_odoo = ProjectConfigOdoo( config.deploy_path, project_directories, config.odoo.serie); project_odoo.server_user = config.odoo.server_user; project_odoo.server_supervisor = config.odoo.server_supervisor; + project_odoo.server_systemd_service_path = ODOO_SYSTEMD_PATH; auto project = new Project( config.deploy_path, diff --git a/subpackages/lib/source/odood/lib/project/config.d b/subpackages/lib/source/odood/lib/project/config.d index 87a26dbc..7797a98c 100644 --- a/subpackages/lib/source/odood/lib/project/config.d +++ b/subpackages/lib/source/odood/lib/project/config.d @@ -62,9 +62,12 @@ struct ProjectConfigOdoo { /// Managed by OS. ProjectServerSupervisor server_supervisor = ProjectServerSupervisor.Odood; - /// Path to init script, of project's server is managed by init script. + /// Path to init script, if project's server is managed by init script. Path server_init_script_path; + /// Path to systemd service configuration, if project's server is managed by systemd. + Path server_systemd_service_path; + this(in Path project_root, in ProjectConfigDirectories directories, in OdooSerie odoo_serie, @@ -139,6 +142,10 @@ struct ProjectConfigOdoo { } else this.server_supervisor = ProjectServerSupervisor.Odood; + if (config.containsKey("server-init-script-path")) + this.server_init_script_path = Path(config["server-init-script-path"].as!string); + if (config.containsKey("server-systemd-service-path")) + this.server_systemd_service_path = Path(config["server-systemd-service-path"].as!string); } dyaml.Node toYAML() const { @@ -162,9 +169,11 @@ struct ProjectConfigOdoo { break; case ProjectServerSupervisor.InitScript: result["server-supervisor"] = "init-script"; + result["server-init-script-path"] = this.server_init_script_path.toString; break; case ProjectServerSupervisor.Systemd: result["server-supervisor"] = "systemd"; + result["server-systemd-service-path"] = this.server_systemd_service_path.toString; break; } From 397dad038a9712d68e8d3de3cb294c3ad2a516c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Thu, 12 Sep 2024 18:03:58 +0300 Subject: [PATCH 12/51] Make it configurable what supervisor use for deployment --- .../cli/source/odood/cli/commands/deploy.d | 26 ++++ .../lib/source/odood/lib/deploy/config.d | 26 +++- .../lib/source/odood/lib/deploy/odoo.d | 143 +++++++++++++++--- subpackages/lib/source/odood/lib/venv.d | 3 + 4 files changed, 176 insertions(+), 22 deletions(-) diff --git a/subpackages/cli/source/odood/cli/commands/deploy.d b/subpackages/cli/source/odood/cli/commands/deploy.d index 0df1edcb..2dc478da 100644 --- a/subpackages/cli/source/odood/cli/commands/deploy.d +++ b/subpackages/cli/source/odood/cli/commands/deploy.d @@ -44,9 +44,16 @@ class CommandDeploy: OdoodCommand { null, "db-user", "Database port").defaultValue("odoo")); this.add(new Option( null, "db-password", "Database password").defaultValue("odoo")); + this.add(new Flag( + null, "local-postgres", "Configure local postgresql server")); this.add(new Flag( null, "proxy-mode", "Enable proxy-mode in odoo config")); + + this.add(new Option( + null, "supervisor", "What superwisor to use for deployment.") + .defaultValue("systemd") + .acceptsValues(["odood", "init-script", "systemd"])); } DeployConfig parseDeployOptions(ProgramArgs args) { @@ -69,6 +76,25 @@ class CommandDeploy: OdoodCommand { if (args.flag("proxy-mode")) config.odoo.proxy_mode = true; + + if (args.flag("local-postgres")) + config.database.local_postgres = true; + + if (args.option("supervisor")) + switch(args.option("supervisor")) { + case "odood": + config.odoo.server_supervisor = ProjectServerSupervisor.Odood; + break; + case "init-script": + config.odoo.server_supervisor = ProjectServerSupervisor.InitScript; + break; + case "systemd": + config.odoo.server_supervisor = ProjectServerSupervisor.Systemd; + break; + default: + assert(0, "Not supported supervisor"); + } + return config; } diff --git a/subpackages/lib/source/odood/lib/deploy/config.d b/subpackages/lib/source/odood/lib/deploy/config.d index 7d04ef21..81031283 100644 --- a/subpackages/lib/source/odood/lib/deploy/config.d +++ b/subpackages/lib/source/odood/lib/deploy/config.d @@ -6,7 +6,10 @@ private import thepath: Path; private import odood.lib.odoo.config: initOdooConfig; private import odood.lib.project: Project, OdooInstallType; -private import odood.lib.project.config: ProjectServerSupervisor; +private import odood.lib.project.config: + ProjectServerSupervisor, + ProjectConfigDirectories, + ProjectConfigOdoo; private import odood.utils.odoo.serie: OdooSerie; private import odood.utils: generateRandomString; @@ -30,6 +33,10 @@ struct DeployConfigOdoo { string server_user="odoo"; ProjectServerSupervisor server_supervisor=ProjectServerSupervisor.Systemd; + Path server_init_script_path = Path( + "/", "etc", "init.d", "odoo"); + Path server_systemd_service_path = Path( + "/", "etc", "systemd", "system", "odoo.service"); } @@ -71,4 +78,21 @@ struct DeployConfig { return odoo_config; } + + /** Prepare Odood project for deployment + **/ + auto prepareOdoodProject() const { + auto project_directories = ProjectConfigDirectories(this.deploy_path); + auto project_odoo = ProjectConfigOdoo( + this.deploy_path, project_directories, this.odoo.serie); + project_odoo.server_user = this.odoo.server_user; + project_odoo.server_supervisor = this.odoo.server_supervisor; + project_odoo.server_systemd_service_path = this.odoo.server_systemd_service_path; + project_odoo.server_init_script_path = this.odoo.server_init_script_path; + + return new Project( + this.deploy_path, + project_directories, + project_odoo); + } } diff --git a/subpackages/lib/source/odood/lib/deploy/odoo.d b/subpackages/lib/source/odood/lib/deploy/odoo.d index d81846f1..0883da57 100644 --- a/subpackages/lib/source/odood/lib/deploy/odoo.d +++ b/subpackages/lib/source/odood/lib/deploy/odoo.d @@ -13,22 +13,119 @@ private import theprocess: Process; private import odood.utils.odoo.serie: OdooSerie; private import odood.lib.project: Project, ODOOD_SYSTEM_CONFIG_PATH; -private import odood.lib.project.config: - ProjectConfigDirectories, ProjectConfigOdoo; +private import odood.lib.project.config: ProjectServerSupervisor; private import odood.lib.deploy.config: DeployConfig; private import odood.lib.deploy.utils: checkSystemUserExists, createSystemUser; -immutable auto ODOO_SYSTEMD_PATH = Path( - "/", "etc", "systemd", "system", "odoo.service"); +private void deployInitScript(in Project project) { + + infof("Configuring init script for Odoo..."); + + // Configure systemd + project.odoo.server_init_script_path.writeFile( +i"#!/bin/bash +### BEGIN INIT INFO +# Provides: odoo +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start odoo daemon at boot time +# Description: Enable service provided by daemon. +# X-Interactive: true +### END INIT INFO +## more info: http://wiki.debian.org/LSBInitScripts + +. /lib/lsb/init-functions + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:$(project.venv.bin_path.toString) +DAEMON=$(project.server.scriptPath.toString) +NAME=odoo +DESC=odoo +CONFIG=$(project.odoo.configfile.toString) +LOGFILE=$(project.odoo.logfile.toString) +PIDFILE=$(project.odoo.pidfile.toString).pid +USER=$(project.odoo.server_user) +export LOGNAME=$USER + +test -x $DAEMON || exit 0 +set -e + +function _start() { + start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE +} + +function _stop() { + start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --retry 3 + rm -f $PIDFILE +} + +function _status() { + start-stop-daemon --status --quiet --pidfile $PIDFILE + return $? +} + + +case \"$1\" in + start) + echo -n \"Starting $DESC: \" + _start + echo \"ok\" + ;; + stop) + echo -n \"Stopping $DESC: \" + _stop + echo \"ok\" + ;; + restart|force-reload) + echo -n \"Restarting $DESC: \" + _stop + sleep 1 + _start + echo \"ok\" + ;; + status) + echo -n \"Status of $DESC: \" + _status && echo \"running\" || echo \"stopped\" + ;; + *) + N=/etc/init.d/$NAME + echo \"Usage: $N {start|stop|restart|force-reload|status}\" >&2 + exit 1 + ;; +esac + +exit 0 +".text); + + // Set access rights for systemd config + project.odoo.server_init_script_path.setAttributes(octal!755); + project.odoo.server_init_script_path.chown("root", "root"); + + // Enable systemd service for Odoo + Process("update-rc.d") + .withArgs("odoo", "defaults") + .execute + .ensureOk(true); + infof("Init script configred successfully. Odoo will be started at startup."); + + //infof("Starting Odoo via init script."); + //Process(project.odoo.server_init_script_path) + //.withArgs("start") + //.execute + //.ensureOk(true); + //infof("Odoo seems to be started"); +} + private void deploySystemdConfig(in Project project) { infof("Configuring systemd daemon for Odoo..."); // Configure systemd - ODOO_SYSTEMD_PATH.writeFile( + project.odoo.server_systemd_service_path.writeFile( i"[Unit] Description=Odoo Open Source ERP and CRM After=network.target @@ -37,7 +134,7 @@ After=network.target Type=simple User=$(project.odoo.server_user) Group=$(project.odoo.server_user) -ExecStart=%(project.server.scriptPath) --config $(project.odoo.configfile) +ExecStart=$(project.server.scriptPath) --config $(project.odoo.configfile) KillMode=mixed [Install] @@ -45,8 +142,8 @@ WantedBy=multi-user.target ".text); // Set access rights for systemd config - ODOO_SYSTEMD_PATH.setAttributes(octal!755); - ODOO_SYSTEMD_PATH.chown("root", "root"); + project.odoo.server_systemd_service_path.setAttributes(octal!755); + project.odoo.server_systemd_service_path.chown("root", "root"); // Enable systemd service for Odoo Process("systemctl") @@ -114,19 +211,13 @@ Project deployOdoo(in DeployConfig config) { infof("Deploying Odoo %s to %s", config.odoo.serie, config.deploy_path); // TODO: Move this configuration to Deploy config - auto project_directories = ProjectConfigDirectories(config.deploy_path); - auto project_odoo = ProjectConfigOdoo( - config.deploy_path, project_directories, config.odoo.serie); - project_odoo.server_user = config.odoo.server_user; - project_odoo.server_supervisor = config.odoo.server_supervisor; - project_odoo.server_systemd_service_path = ODOO_SYSTEMD_PATH; - - auto project = new Project( - config.deploy_path, - project_directories, - project_odoo); + auto project = config.prepareOdoodProject(); + // We need to keep reference on odoo_config to make initialize work. + // TODO: Fix this auto odoo_config = config.prepareOdooConfig(project); + + // Initialize project. project.initialize( odoo_config, config.py_version, @@ -145,8 +236,18 @@ Project deployOdoo(in DeployConfig config) { deployLogrotateConfig(project); // Configure systemd - // TODO: make it optional - deploySystemdConfig(project); + final switch(config.odoo.server_supervisor) { + case ProjectServerSupervisor.Odood: + // Do nothing. + // TODO: May be it have sense to create some link in /usr/sbin for Odoo? + break; + case ProjectServerSupervisor.InitScript: + deployInitScript(project); + break; + case ProjectServerSupervisor.Systemd: + deploySystemdConfig(project); + break; + } infof("Odoo deployed successfully."); return project; diff --git a/subpackages/lib/source/odood/lib/venv.d b/subpackages/lib/source/odood/lib/venv.d index d742aa43..aab722fc 100644 --- a/subpackages/lib/source/odood/lib/venv.d +++ b/subpackages/lib/source/odood/lib/venv.d @@ -69,6 +69,9 @@ const struct VirtualEnv { /// Path where virtualenv isntalled @safe pure nothrow const(Path) path() const { return _path; } + /// Bin path inside this virtualenv + @safe pure nothrow const(Path) bin_path() const {return _path.join("bin"); } + /// Serie of python used for this virtualenv (py2 or py3) @safe const(PySerie) py_serie() const { return _py_serie; } From f40827b38257dbfc0d57eec936e6f7312d55e7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Thu, 12 Sep 2024 18:04:57 +0300 Subject: [PATCH 13/51] Use 'init-script' supervisor for test deployments --- .github/workflows/test-deployments.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-deployments.yml b/.github/workflows/test-deployments.yml index bdca9fb0..dab7bb1b 100644 --- a/.github/workflows/test-deployments.yml +++ b/.github/workflows/test-deployments.yml @@ -83,7 +83,7 @@ jobs: run: chmod a+x ./build/odood - name: Run tests - run: ./build/odood deploy -v ${{ matrix.odoo_version }} + run: ./build/odood deploy -v ${{ matrix.odoo_version }} --supervisor=init-script # TODO: Add test some operations with this instance From 83aa816166c3196e6dff6cc2455f10da32bf78c5 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Sep 2024 22:46:37 +0300 Subject: [PATCH 14/51] Further work on deployment of Odoo. Support for local postgres config --- .github/workflows/test-deployments.yml | 4 +- .../cli/source/odood/cli/commands/deploy.d | 36 +++++------ .../lib/source/odood/lib/deploy/config.d | 59 +++++++++++++++++- .../lib/source/odood/lib/deploy/exception.d | 11 ++++ .../lib/source/odood/lib/deploy/odoo.d | 61 +++++++++++++------ .../lib/source/odood/lib/deploy/package.d | 2 +- .../lib/source/odood/lib/server/server.d | 21 +++++-- 7 files changed, 142 insertions(+), 52 deletions(-) create mode 100644 subpackages/lib/source/odood/lib/deploy/exception.d diff --git a/.github/workflows/test-deployments.yml b/.github/workflows/test-deployments.yml index dab7bb1b..20d9032c 100644 --- a/.github/workflows/test-deployments.yml +++ b/.github/workflows/test-deployments.yml @@ -53,7 +53,7 @@ jobs: - "ubuntu:24.04" odoo_version: - "17.0" - #- "16.0" + - "16.0" runs-on: ubuntu-22.04 needs: - compile-ubuntu-20_04 @@ -82,7 +82,7 @@ jobs: - name: Make test build executable run: chmod a+x ./build/odood - - name: Run tests + - name: Deploy with init-script run: ./build/odood deploy -v ${{ matrix.odoo_version }} --supervisor=init-script # TODO: Add test some operations with this instance diff --git a/subpackages/cli/source/odood/cli/commands/deploy.d b/subpackages/cli/source/odood/cli/commands/deploy.d index 2dc478da..fb878a95 100644 --- a/subpackages/cli/source/odood/cli/commands/deploy.d +++ b/subpackages/cli/source/odood/cli/commands/deploy.d @@ -6,6 +6,7 @@ private import std.logger; private import std.format: format; private import std.exception: enforce, errnoEnforce; private import std.conv: octal; +private import std.range: empty; private import thepath: Path; private import theprocess: Process; @@ -14,10 +15,9 @@ private import dini: Ini; private import odood.cli.core: OdoodCommand, OdoodCLIException; private import odood.lib.project: - Project, OdooInstallType, ODOOD_SYSTEM_CONFIG_PATH; + Project, OdooInstallType; private import odood.lib.project.config: ProjectServerSupervisor; private import odood.lib.odoo.config: initOdooConfig; -private import odood.lib.postgres: createNewPostgresUser; private import odood.utils.odoo.serie: OdooSerie; private import odood.utils: generateRandomString; @@ -50,6 +50,9 @@ class CommandDeploy: OdoodCommand { this.add(new Flag( null, "proxy-mode", "Enable proxy-mode in odoo config")); + this.add(new Flag( + null, "enable-logrotate", "Enable logrotate for Odoo.")); + this.add(new Option( null, "supervisor", "What superwisor to use for deployment.") .defaultValue("systemd") @@ -80,6 +83,14 @@ class CommandDeploy: OdoodCommand { if (args.flag("local-postgres")) config.database.local_postgres = true; + if (config.database.local_postgres && config.database.password.empty) + // Generate default password + config.database.password = generateRandomString( + DEFAULT_PASSWORD_LEN); + + if (args.flag("enable-logrotate")) + config.logrotate_enable = true; + if (args.option("supervisor")) switch(args.option("supervisor")) { case "odood": @@ -103,26 +114,7 @@ class CommandDeploy: OdoodCommand { enforce!OdoodCLIException( geteuid == 0 && getegid == 0, "This command must be ran as root!"); - - enforce!OdoodCLIException( - deploy_config.odoo.serie.isValid, - "Odoo version %s is not valid".format(args.option("odoo-version"))); - enforce!OdoodCLIException( - !deploy_config.deploy_path.exists, - "Deploy path %s already exists. ".format(deploy_config.deploy_path) ~ - "It seems that there was attempt to install Odoo. " ~ - "This command can install Odoo only on clean machine."); - enforce!OdoodCLIException( - !ODOOD_SYSTEM_CONFIG_PATH.exists, - "Odood system-wide config already exists at %s. ".format(ODOOD_SYSTEM_CONFIG_PATH) ~ - "It seems that there was attempt to install Odoo. " ~ - "This command can install Odoo only on clean machine."); - enforce!OdoodCLIException( - !Path("etc", "logrotate.d", "odoo").exists, - "It seems that Odoo config for logrotate already exists!"); - enforce!OdoodCLIException( - !Path("etc", "systemd", "system", "odoo.service").exists, - "It seems that systemd service for Odoo already exists!"); + deploy_config.ensureValid(); } public override void execute(ProgramArgs args) { diff --git a/subpackages/lib/source/odood/lib/deploy/config.d b/subpackages/lib/source/odood/lib/deploy/config.d index 81031283..7858720e 100644 --- a/subpackages/lib/source/odood/lib/deploy/config.d +++ b/subpackages/lib/source/odood/lib/deploy/config.d @@ -1,21 +1,27 @@ module odood.lib.deploy.config; private import std.conv: to; +private import std.range: empty; +private import std.exception: enforce; +private import std.format: format; private import thepath: Path; private import odood.lib.odoo.config: initOdooConfig; -private import odood.lib.project: Project, OdooInstallType; +private import odood.lib.project: + Project, + OdooInstallType, + ODOOD_SYSTEM_CONFIG_PATH; private import odood.lib.project.config: ProjectServerSupervisor, ProjectConfigDirectories, ProjectConfigOdoo; +private import odood.lib.deploy.exception: OdoodDeployException; private import odood.utils.odoo.serie: OdooSerie; private import odood.utils: generateRandomString; immutable auto DEFAULT_PASSWORD_LEN = 32; - struct DeployConfigDatabase { string host="localhost"; string port="5432"; @@ -38,6 +44,7 @@ struct DeployConfigOdoo { Path server_systemd_service_path = Path( "/", "etc", "systemd", "system", "odoo.service"); + Path pidfile = Path("/", "var", "run", "odoo.pid"); } struct DeployConfig { @@ -49,6 +56,53 @@ struct DeployConfig { DeployConfigDatabase database; DeployConfigOdoo odoo; + bool logrotate_enable = false; + Path logrotate_config_path = Path("/", "etc", "logrotate.d", "odoo"); + + /** Validate deploy config + * Throw exception if config is not valid. + **/ + void ensureValid() const { + enforce!OdoodDeployException( + this.odoo.serie.isValid, + "Odoo version is not valid"); + enforce!OdoodDeployException( + !this.deploy_path.exists, + "Deploy path %s already exists. ".format(this.deploy_path) ~ + "It seems that there was attempt to install Odoo. " ~ + "This command can install Odoo only on clean machine."); + enforce!OdoodDeployException( + !ODOOD_SYSTEM_CONFIG_PATH.exists, + "Odood system-wide config already exists at %s. ".format(ODOOD_SYSTEM_CONFIG_PATH) ~ + "It seems that there was attempt to install Odoo. " ~ + "This command can install Odoo only on clean machine."); + + if (this.logrotate_enable) + enforce!OdoodDeployException( + !Path("etc", "logrotate.d", "odoo").exists, + "It seems that Odoo config for logrotate already exists!"); + + final switch(this.odoo.server_supervisor) { + case ProjectServerSupervisor.Odood: + // Do nothing, no additional check needed. + break; + case ProjectServerSupervisor.InitScript: + enforce!OdoodDeployException( + !this.odoo.server_init_script_path.exists, + "It seems that init.d script for Odoo already exists!"); + break; + case ProjectServerSupervisor.Systemd: + enforce!OdoodDeployException( + !this.odoo.server_systemd_service_path.exists, + "It seems that systemd service for Odoo already exists!"); + break; + } + + enforce!OdoodDeployException( + !this.database.password.empty, + "Password for database must not be empty!"); + } + auto prepareOdooConfig(in Project project) const in ( project.odoo.serie == this.odoo.serie @@ -89,6 +143,7 @@ struct DeployConfig { project_odoo.server_supervisor = this.odoo.server_supervisor; project_odoo.server_systemd_service_path = this.odoo.server_systemd_service_path; project_odoo.server_init_script_path = this.odoo.server_init_script_path; + project_odoo.pidfile = this.odoo.pidfile; return new Project( this.deploy_path, diff --git a/subpackages/lib/source/odood/lib/deploy/exception.d b/subpackages/lib/source/odood/lib/deploy/exception.d new file mode 100644 index 00000000..f819d45d --- /dev/null +++ b/subpackages/lib/source/odood/lib/deploy/exception.d @@ -0,0 +1,11 @@ +module odood.lib.deploy.exception; + +private import std.exception: basicExceptionCtors; + +private import odood.exception: OdoodException; + + +class OdoodDeployException : OdoodException { + mixin basicExceptionCtors; +} + diff --git a/subpackages/lib/source/odood/lib/deploy/odoo.d b/subpackages/lib/source/odood/lib/deploy/odoo.d index 0883da57..c64da415 100644 --- a/subpackages/lib/source/odood/lib/deploy/odoo.d +++ b/subpackages/lib/source/odood/lib/deploy/odoo.d @@ -5,7 +5,7 @@ private import core.sys.posix.pwd: getpwnam, passwd; private import std.logger: infof; private import std.exception: enforce, errnoEnforce; -private import std.conv: text, octal; +private import std.conv: to, text, octal; private import std.format: format; private import thepath: Path; @@ -42,9 +42,9 @@ i"#!/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:$(project.venv.bin_path.toString) DAEMON=$(project.server.scriptPath.toString) -NAME=odoo -DESC=odoo -CONFIG=$(project.odoo.configfile.toString) + NAME=odoo + DESC=odoo + CONFIG=$(project.odoo.configfile.toString) LOGFILE=$(project.odoo.logfile.toString) PIDFILE=$(project.odoo.pidfile.toString).pid USER=$(project.odoo.server_user) @@ -110,13 +110,6 @@ exit 0 .execute .ensureOk(true); infof("Init script configred successfully. Odoo will be started at startup."); - - //infof("Starting Odoo via init script."); - //Process(project.odoo.server_init_script_path) - //.withArgs("start") - //.execute - //.ensureOk(true); - //infof("Odoo seems to be started"); } @@ -163,11 +156,9 @@ WantedBy=multi-user.target } -private void deployLogrotateConfig(in Project project) { - immutable auto logrotate_config_path = Path("/", "etc", "logrotate.d", "odoo"); - +private void deployLogrotateConfig(in Project project, in DeployConfig config) { infof("Configuring logrotate for Odoo..."); - logrotate_config_path.writeFile( + config.logrotate_config_path.writeFile( i"$(project.directories.log.toString)/*.log { copytruncate missingok @@ -175,12 +166,40 @@ i"$(project.directories.log.toString)/*.log { }".text); // Set access rights for logrotate config - logrotate_config_path.setAttributes(octal!755); - logrotate_config_path.chown("root", "root"); + config.logrotate_config_path.setAttributes(octal!755); + config.logrotate_config_path.chown("root", "root"); infof("Logrotate configured successfully."); } + +private void deployConfigurePostgresql(in Project project, in DeployConfig config) { + // Check if postgresql user for Odoo exists + auto output = Process("psql") + .setArgs([ + "-c", + i"SELECT count(*) FROM pg_user WHERE usename = '$(config.database.user)';".text, + ]) + .withUser("postgres") + .execute + .ensureStatus(true) + .output; + + if (output.to!int == 0) { + // Create postgresql user if "local-postgres" is selected and no user exists + infof("Creating postgresql user '%s' for Odoo...", config.database.user); + Process("psql") + .setArgs([ + "-c", + i"CREATE USER \"$(config.database.user)\" WITH CREATEDB PASSWORD '$(config.database.password)'".text, + ]) + .withUser("postgres") + .execute + .ensureStatus(true); + infof("Postgresql user '%s' for Odoo created successfully.", config.database.user); + } +} + private void setAccessRights(in Project project) { import std.string: toStringz; // Get info about odoo user @@ -231,9 +250,13 @@ Project deployOdoo(in DeployConfig config) { // Set access rights for Odoo installed project.setAccessRights(); + // Create postgresql user if "local-postgres" is selected and no user exists + if (config.database.local_postgres) + deployConfigurePostgresql(project, config); + // Configure logrotate - // TODO: make it optional - deployLogrotateConfig(project); + if (config.logrotate_enable) + deployLogrotateConfig(project, config); // Configure systemd final switch(config.odoo.server_supervisor) { diff --git a/subpackages/lib/source/odood/lib/deploy/package.d b/subpackages/lib/source/odood/lib/deploy/package.d index 35552919..f0d4bfb9 100644 --- a/subpackages/lib/source/odood/lib/deploy/package.d +++ b/subpackages/lib/source/odood/lib/deploy/package.d @@ -1,4 +1,4 @@ module odood.lib.deploy; -public import odood.lib.deploy.config: DeployConfig; +public import odood.lib.deploy.config: DeployConfig, DEFAULT_PASSWORD_LEN; public import odood.lib.deploy.odoo: deployOdoo; diff --git a/subpackages/lib/source/odood/lib/server/server.d b/subpackages/lib/source/odood/lib/server/server.d index eddd54c5..878f0ddc 100644 --- a/subpackages/lib/source/odood/lib/server/server.d +++ b/subpackages/lib/source/odood/lib/server/server.d @@ -83,13 +83,22 @@ struct OdooServer { * - -2 if process specified in pid file is not running **/ pid_t getPid() const { - if (_project.odoo.pidfile.exists) { - auto pid = _project.odoo.pidfile.readFileText.strip.to!pid_t; - if (isProcessRunning(pid)) - return pid; - return -2; + final switch(_project.odoo.server_supervisor) { + case ProjectServerSupervisor.Odood, ProjectServerSupervisor.InitScript: + if (_project.odoo.pidfile.exists) { + auto pid = _project.odoo.pidfile.readFileText.strip.to!pid_t; + if (isProcessRunning(pid)) + return pid; + return -2; + } + return -1; + case ProjectServerSupervisor.Systemd: + return Process("systemctl") + .withArgs("show", "--property=MainPID", "--value", "odoo") + .execute + .ensureOk(true) + .output.to!pid_t; } - return -1; } /** Get environment variables to apply when running Odoo server. From 37c3f8a6e6557f702b6e8403b8672bb97f40e572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Fri, 13 Sep 2024 12:23:12 +0300 Subject: [PATCH 15/51] Refactoring and improvements of deployments --- .../cli/source/odood/cli/commands/deploy.d | 5 +- .../lib/source/odood/lib/deploy/config.d | 9 ++ .../lib/source/odood/lib/deploy/odoo.d | 92 ++++++++----------- .../lib/source/odood/lib/deploy/utils.d | 51 ++++++++-- 4 files changed, 92 insertions(+), 65 deletions(-) diff --git a/subpackages/cli/source/odood/cli/commands/deploy.d b/subpackages/cli/source/odood/cli/commands/deploy.d index fb878a95..1c9e5c1a 100644 --- a/subpackages/cli/source/odood/cli/commands/deploy.d +++ b/subpackages/cli/source/odood/cli/commands/deploy.d @@ -84,7 +84,10 @@ class CommandDeploy: OdoodCommand { config.database.local_postgres = true; if (config.database.local_postgres && config.database.password.empty) - // Generate default password + /* Generate default password. + * Here we assume that new user will be created in local postgres. + * Most likely case. + */ config.database.password = generateRandomString( DEFAULT_PASSWORD_LEN); diff --git a/subpackages/lib/source/odood/lib/deploy/config.d b/subpackages/lib/source/odood/lib/deploy/config.d index 7858720e..18eeaba0 100644 --- a/subpackages/lib/source/odood/lib/deploy/config.d +++ b/subpackages/lib/source/odood/lib/deploy/config.d @@ -17,6 +17,7 @@ private import odood.lib.project.config: ProjectConfigDirectories, ProjectConfigOdoo; private import odood.lib.deploy.exception: OdoodDeployException; +private import odood.lib.deploy.utils: dpkgCheckPackageInstalled; private import odood.utils.odoo.serie: OdooSerie; private import odood.utils: generateRandomString; @@ -101,8 +102,16 @@ struct DeployConfig { enforce!OdoodDeployException( !this.database.password.empty, "Password for database must not be empty!"); + + if (this.database.local_postgres) + enforce!OdoodDeployException( + !dpkgCheckPackageInstalled("potgresql"), + "Local postgres requested, but 'postgresql' package is not installed!"); } + /** Prepare odoo configuration file for this deployment + * based on this deployment configuration + **/ auto prepareOdooConfig(in Project project) const in ( project.odoo.serie == this.odoo.serie diff --git a/subpackages/lib/source/odood/lib/deploy/odoo.d b/subpackages/lib/source/odood/lib/deploy/odoo.d index c64da415..a2b842df 100644 --- a/subpackages/lib/source/odood/lib/deploy/odoo.d +++ b/subpackages/lib/source/odood/lib/deploy/odoo.d @@ -7,6 +7,7 @@ private import std.logger: infof; private import std.exception: enforce, errnoEnforce; private import std.conv: to, text, octal; private import std.format: format; +private import std.string: toStringz; private import thepath: Path; private import theprocess: Process; @@ -16,7 +17,11 @@ private import odood.lib.project: Project, ODOOD_SYSTEM_CONFIG_PATH; private import odood.lib.project.config: ProjectServerSupervisor; private import odood.lib.deploy.config: DeployConfig; -private import odood.lib.deploy.utils: checkSystemUserExists, createSystemUser; +private import odood.lib.deploy.utils: + checkSystemUserExists, + createSystemUser, + postgresCheckUserExists, + postgresCreateUser; private void deployInitScript(in Project project) { @@ -173,36 +178,30 @@ i"$(project.directories.log.toString)/*.log { } -private void deployConfigurePostgresql(in Project project, in DeployConfig config) { - // Check if postgresql user for Odoo exists - auto output = Process("psql") - .setArgs([ - "-c", - i"SELECT count(*) FROM pg_user WHERE usename = '$(config.database.user)';".text, - ]) - .withUser("postgres") - .execute - .ensureStatus(true) - .output; - - if (output.to!int == 0) { - // Create postgresql user if "local-postgres" is selected and no user exists - infof("Creating postgresql user '%s' for Odoo...", config.database.user); - Process("psql") - .setArgs([ - "-c", - i"CREATE USER \"$(config.database.user)\" WITH CREATEDB PASSWORD '$(config.database.password)'".text, - ]) - .withUser("postgres") - .execute - .ensureStatus(true); - infof("Postgresql user '%s' for Odoo created successfully.", config.database.user); - } -} +/** Deploy Odoo according provided DeployConfig + **/ +Project deployOdoo(in DeployConfig config) { + infof("Deploying Odoo %s to %s", config.odoo.serie, config.deploy_path); + + // TODO: Move this configuration to Deploy config + auto project = config.prepareOdoodProject(); + + // We need to keep reference on odoo_config to make initialize work. + // TODO: Fix this + auto odoo_config = config.prepareOdooConfig(project); + + // Initialize project. + project.initialize( + odoo_config, + config.py_version, + config.node_version, + config.install_type); + project.save(ODOOD_SYSTEM_CONFIG_PATH); + + if (!checkSystemUserExists(project.odoo.server_user)) + createSystemUser(project.project_root, project.odoo.server_user); -private void setAccessRights(in Project project) { - import std.string: toStringz; - // Get info about odoo user + // Get info about odoo user (that is needed to set up access rights for Odoo files auto pw_odoo = getpwnam(project.odoo.server_user.toStringz); errnoEnforce( pw_odoo !is null, @@ -224,35 +223,16 @@ private void setAccessRights(in Project project) { // thus, Odoo will be able to create files there, // but will not be allowed to change existing files. project.project_root.chown(pw_odoo.pw_uid, pw_odoo.pw_gid); -} - -Project deployOdoo(in DeployConfig config) { - infof("Deploying Odoo %s to %s", config.odoo.serie, config.deploy_path); - - // TODO: Move this configuration to Deploy config - auto project = config.prepareOdoodProject(); - - // We need to keep reference on odoo_config to make initialize work. - // TODO: Fix this - auto odoo_config = config.prepareOdooConfig(project); - - // Initialize project. - project.initialize( - odoo_config, - config.py_version, - config.node_version, - config.install_type); - project.save(ODOOD_SYSTEM_CONFIG_PATH); - - if (!checkSystemUserExists(project.odoo.server_user)) - createSystemUser(project.project_root, project.odoo.server_user); - - // Set access rights for Odoo installed - project.setAccessRights(); // Create postgresql user if "local-postgres" is selected and no user exists if (config.database.local_postgres) - deployConfigurePostgresql(project, config); + /* In this case we need to create postgres user + * only if it does not exists yet. + * If user already exists, we expect, + * that user provided correct password for it. + */ + if (!postgresCheckUserExists(config.database.user)) + postgresCreateUser(config.database.user, config.database.password); // Configure logrotate if (config.logrotate_enable) diff --git a/subpackages/lib/source/odood/lib/deploy/utils.d b/subpackages/lib/source/odood/lib/deploy/utils.d index 516d48ca..638db77a 100644 --- a/subpackages/lib/source/odood/lib/deploy/utils.d +++ b/subpackages/lib/source/odood/lib/deploy/utils.d @@ -1,7 +1,9 @@ module odood.lib.deploy.utils; +private import std.logger: infof; private import std.format: format; private import std.exception: enforce, errnoEnforce; +private import std.conv: to, text; private import core.sys.posix.unistd: geteuid, getegid; private import core.sys.posix.pwd: getpwnam_r, passwd; @@ -40,15 +42,48 @@ void createSystemUser(in Path home, in string name) { } -void createPostgresUser(in string username, in string password) { +/** Check if PostgreSQL user with provided username exists + **/ +bool postgresCheckUserExists(in string username) { + auto output = Process("psql") + .setArgs([ + "-c", + i"SELECT count(*) FROM pg_user WHERE usename = '$(username)';".text, + ]) + .withUser("postgres") + .execute + .ensureOk(true) + .output; + + return output.to!int == 0; +} + + +/** Create new PostgreSQL user for Odoo with provided credentials + **/ +void postgresCreateUser(in string username, in string password) { + infof("Creating postgresql user '%s' for Odoo...", username); Process("psql") + .setArgs([ + "-c", + i"CREATE USER \"$(username)\" WITH CREATEDB PASSWORD '$(password)'".text, + ]) .withUser("postgres") - .withArgs( - "psql", "-c", - "CREATE USER \"%s\" WITH CREATEDB PASSWORD '%s'".format( - username, password), - ) - .execute() - .ensureOk(true); + .execute + .ensureStatus(true); + infof("Postgresql user '%s' for Odoo created successfully.", username); } + +/** Check if debian package is installed in system + **/ +bool dpkgCheckPackageInstalled(in string package_name) { + auto result = Process("dpkg-query") + .withArgs("--show", "--showformat='${db:Status-Status}'", package_name) + .execute; + if (result.isNotOk) + return false; + if (result.output == "installed") + return true; + return false; +} From 21de7c9e9ca16f408bebe76587a486b106bcb39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Fri, 13 Sep 2024 13:14:03 +0300 Subject: [PATCH 16/51] Update readme and version --- CHANGELOG.md | 5 +++-- subpackages/lib/source/odood/lib/package.d | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af406e5..9c8a4f98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ # Changelog -## Release 0.1.1 (unreleased) +## Release 0.2.0 (unreleased) ### Added -- New commaand `odood odoo run` that allows to run Odoo itself. +- New command `odood odoo run` that allows to run Odoo itself. +- New command `odood deploy` that could be used to deploy production-ready Odoo instance. ### Changed diff --git a/subpackages/lib/source/odood/lib/package.d b/subpackages/lib/source/odood/lib/package.d index eef84386..beaa5535 100644 --- a/subpackages/lib/source/odood/lib/package.d +++ b/subpackages/lib/source/odood/lib/package.d @@ -1,6 +1,6 @@ module odood.lib; -public immutable string _version = "0.1.0"; +public immutable string _version = "0.2.0"; public import odood.lib.project; From 0edc5b899d4ce5b09c4fef69c9525dde6e9edeac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Fri, 13 Sep 2024 17:45:48 +0300 Subject: [PATCH 17/51] [CI] Add ability to use pre-releases --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ef6cbb0..3ab1d0cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ on: push: tags: - 'v*.*.*' - - 'v*.*.*-RC*' + - 'v*.*.*-*' env: ODOOD_DLANG_COMPILER: ldc-1.39.0 @@ -90,10 +90,10 @@ jobs: - name: 'Show directory structure' run: ls -R - - name: Check RC Release + - name: Check RC/alpha Release id: check-rc-release run: | - if [[ ${{ github.event.ref }} =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+-(rc|RC)[0-9]+$ ]]; then + if [[ ${{ github.event.ref }} =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+-(rc|RC|[0-9a-zA-Z\.\-]+)[0-9]+$ ]]; then echo "is_rc_release=true" >> $GITHUB_OUTPUT elif [[ ${{ github.event.ref }} =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "is_rc_release=false" >> $GITHUB_OUTPUT From 4c30664a9b18fe32e7f70bedd1547500e5bee9e3 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 15 Sep 2024 20:59:16 +0300 Subject: [PATCH 18/51] [FIX] deployment command --- subpackages/lib/source/odood/lib/deploy/utils.d | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/subpackages/lib/source/odood/lib/deploy/utils.d b/subpackages/lib/source/odood/lib/deploy/utils.d index 638db77a..8a683ae3 100644 --- a/subpackages/lib/source/odood/lib/deploy/utils.d +++ b/subpackages/lib/source/odood/lib/deploy/utils.d @@ -1,9 +1,10 @@ module odood.lib.deploy.utils; -private import std.logger: infof; +private import std.logger: infof, tracef; private import std.format: format; private import std.exception: enforce, errnoEnforce; private import std.conv: to, text; +private import std.string: strip; private import core.sys.posix.unistd: geteuid, getegid; private import core.sys.posix.pwd: getpwnam_r, passwd; @@ -47,15 +48,15 @@ void createSystemUser(in Path home, in string name) { bool postgresCheckUserExists(in string username) { auto output = Process("psql") .setArgs([ - "-c", + "-t", "-A", "-c", i"SELECT count(*) FROM pg_user WHERE usename = '$(username)';".text, ]) .withUser("postgres") .execute .ensureOk(true) - .output; + .output.strip; - return output.to!int == 0; + return output.to!int != 0; } @@ -70,7 +71,7 @@ void postgresCreateUser(in string username, in string password) { ]) .withUser("postgres") .execute - .ensureStatus(true); + .ensureOk(true); infof("Postgresql user '%s' for Odoo created successfully.", username); } From f51ad6535f27c22a3c2d589d5acef67e58565a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Mon, 23 Sep 2024 10:18:49 +0300 Subject: [PATCH 19/51] Minor fixes + added some TODO for turther developments --- subpackages/cli/source/odood/cli/commands/odoo.d | 4 ++++ subpackages/cli/source/odood/cli/commands/server.d | 3 +++ subpackages/lib/source/odood/lib/server/server.d | 10 ++++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/subpackages/cli/source/odood/cli/commands/odoo.d b/subpackages/cli/source/odood/cli/commands/odoo.d index acb9a9d3..6b8594a6 100644 --- a/subpackages/cli/source/odood/cli/commands/odoo.d +++ b/subpackages/cli/source/odood/cli/commands/odoo.d @@ -33,6 +33,10 @@ class CommandOdooRun: OdoodCommand { } public override void execute(ProgramArgs args) { + // TODO: May be merge with server/run? + // Also, add ability to update config before running + // Odoo based on environment variables, that will be useful in case, + // when running in docker. Project.loadProject.server.getServerRunner() .addArgs(args.argsRest) .execv; diff --git a/subpackages/cli/source/odood/cli/commands/server.d b/subpackages/cli/source/odood/cli/commands/server.d index 70296269..21305f55 100644 --- a/subpackages/cli/source/odood/cli/commands/server.d +++ b/subpackages/cli/source/odood/cli/commands/server.d @@ -19,6 +19,9 @@ class CommandServerRun: OdoodCommand { this() { super("run", "Run the server."); this.add(new Flag("d", "detach", "Run the server in background.")); + // TODO: Add ability to run with execv (useful in docker) + // TODO: Add ability to update odoo config based on environment, + // that is useful when running inside docker containers } public override void execute(ProgramArgs args) { diff --git a/subpackages/lib/source/odood/lib/server/server.d b/subpackages/lib/source/odood/lib/server/server.d index 878f0ddc..f589ea20 100644 --- a/subpackages/lib/source/odood/lib/server/server.d +++ b/subpackages/lib/source/odood/lib/server/server.d @@ -118,6 +118,8 @@ struct OdooServer { res["OPENERP_SERVER"] = _project.odoo.configfile.toString; res["ODOO_RC"] = _project.odoo.configfile.toString; } + // TODO: Add ability to parse .env files and forward environment variables to Odoo process + // This will allow to run Odoo in docker containers and locally in similar way. return res; } @@ -176,8 +178,7 @@ struct OdooServer { * detach = if set, then run server in background **/ pid_t spawn(bool detach=false) const { - import std.process: Config; - + // TODO: Add ability to handle coverage settings and other odoo options enforce!ServerAlreadyRuningException( !isRunning, "Server already running!"); @@ -189,7 +190,7 @@ struct OdooServer { auto runner = getServerRunner( "--pidfile=%s".format(_project.odoo.pidfile)); if (detach) { - runner.setFlag(Config.detached); + runner.setFlag(std.process.Config.detached); runner.addArgs("--logfile=%s".format(_project.odoo.logfile)); } @@ -236,6 +237,7 @@ struct OdooServer { * env = extra environment variables to pass to the server **/ auto run(in string[] options, in string[string] env=null) const { + // TODO: Use serverRunner instead of venv auto res = _project.venv.run( scriptPath, options, @@ -322,7 +324,7 @@ struct OdooServer { **/ void stopOdoodServer() const { import core.sys.posix.signal: kill, SIGTERM; - import core.stdc.errno; + import core.stdc.errno: ESRCH; import std.exception: ErrnoException; info("Stopping odoo server..."); From 1b25382a428641d3d988cfe04179cea347b93804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Thu, 26 Sep 2024 15:56:40 +0300 Subject: [PATCH 20/51] Avoid using server.run and co, instead use server's runner This is needed to correctly run Odoo, especially in case of production deployments, when Odoo is running as different user. --- .../cli/source/odood/cli/commands/addons.d | 4 +- .../lib/source/odood/lib/addons/manager.d | 30 +++++++++---- .../lib/source/odood/lib/server/exception.d | 7 ---- .../lib/source/odood/lib/server/server.d | 42 +------------------ 4 files changed, 24 insertions(+), 59 deletions(-) diff --git a/subpackages/cli/source/odood/cli/commands/addons.d b/subpackages/cli/source/odood/cli/commands/addons.d index 4946e67c..6323ee4a 100644 --- a/subpackages/cli/source/odood/cli/commands/addons.d +++ b/subpackages/cli/source/odood/cli/commands/addons.d @@ -20,7 +20,7 @@ private import odood.lib.project: Project; private import odood.utils.odoo.serie: OdooSerie; private import odood.utils.addons.addon: OdooAddon; private import odood.lib.odoo.log: OdooLogProcessor; -private import odood.lib.server.exception: ServerCommandFailedException; +private import odood.lib.addons.manager: AddonsInstallUpdateException; /** This exception could be throwed when install/update/uninstall command @@ -489,7 +489,7 @@ class CommandAddonsUpdateInstallUninstall: OdoodCommand { try { // Try to apply delegate dg(db); - } catch (ServerCommandFailedException e) { + } catch (AddonsInstallUpdateException e) { error = true; if (!log_file.isOpen && project.odoo.logfile.exists) diff --git a/subpackages/lib/source/odood/lib/addons/manager.d b/subpackages/lib/source/odood/lib/addons/manager.d index 5174ab57..bb82744e 100644 --- a/subpackages/lib/source/odood/lib/addons/manager.d +++ b/subpackages/lib/source/odood/lib/addons/manager.d @@ -6,7 +6,7 @@ private import std.array: split, empty, array; private import std.string: join, strip, startsWith, toLower; private import std.format: format; private import std.file: SpanMode; -private import std.exception: enforce, ErrnoException; +private import std.exception: enforce, ErrnoException, basicExceptionCtors; private import std.algorithm: map, canFind; private import thepath: Path, createTempPath; @@ -29,6 +29,18 @@ immutable bool DEFAULT_INSTALL_PY_REQUREMENTS = true; /// Install python dependencies from addon manifest by default immutable bool DEFAULT_INSTALL_MANIFEST_REQUREMENTS = false; +class AddonsInstallUpdateException: OdoodException { + mixin basicExceptionCtors; +} + +class AddonsInstallException : AddonsInstallUpdateException { + mixin basicExceptionCtors; +} + +class AddonsUpdateException : AddonsInstallUpdateException { + mixin basicExceptionCtors; +} + /// Struct that provide API to manage odoo addons for the project struct AddonManager { @@ -308,30 +320,30 @@ struct AddonManager { in cmdIU cmd, in string[string] env=null) const { - string[] server_opts=[ + // Initialize server runner configuration + auto runner = _project.server.getServerRunner( "-d", database, "--max-cron-threads=0", "--stop-after-init", _project.odoo.serie <= OdooSerie(10) ? "--no-xmlrpc" : "--no-http", "--pidfile=", // We must not write to pidfile to avoid conflicts with running Odoo "--logfile=%s".format(_project.odoo.logfile.toString), - ]; - + ).withEnv(env); if (!_project.hasDatabaseDemoData(database)) - server_opts ~= ["--without-demo=all"]; + runner.addArgs("--without-demo=all"); auto addon_names_csv = addon_names.join(","); final switch(cmd) { case cmdIU.install: infof("Installing addons (db=%s): %s", database, addon_names_csv); - _project.server(_test_mode).runE( - server_opts ~ ["--init=%s".format(addon_names_csv)], env); + runner.addArgs("--init=%s".format(addon_names_csv)) + .execute.ensureOk!AddonsInstallException(true); infof("Installation of addons for database %s completed!", database); break; case cmdIU.update: infof("Updating addons (db=%s): %s", database, addon_names_csv); - _project.server(_test_mode).runE( - server_opts ~ ["--update=%s".format(addon_names_csv)], env); + runner.addArgs("--update=%s".format(addon_names_csv)) + .execute.ensureOk!AddonsUpdateException(true); infof("Update of addons for database %s completed!", database); break; case cmdIU.uninstall: diff --git a/subpackages/lib/source/odood/lib/server/exception.d b/subpackages/lib/source/odood/lib/server/exception.d index 7ba5f0c1..4089dbaf 100644 --- a/subpackages/lib/source/odood/lib/server/exception.d +++ b/subpackages/lib/source/odood/lib/server/exception.d @@ -14,10 +14,3 @@ class ServerAlreadyRuningException : ServerException { mixin basicExceptionCtors; } - - -class ServerCommandFailedException : ServerException -{ - mixin basicExceptionCtors; -} - diff --git a/subpackages/lib/source/odood/lib/server/server.d b/subpackages/lib/source/odood/lib/server/server.d index f589ea20..c8794e8f 100644 --- a/subpackages/lib/source/odood/lib/server/server.d +++ b/subpackages/lib/source/odood/lib/server/server.d @@ -230,46 +230,6 @@ struct OdooServer { return pipeServerLog(CoverageOptions(false), options); } - /** Run server with provided options. - * - * Params: - * options = list of options to pass to the server - * env = extra environment variables to pass to the server - **/ - auto run(in string[] options, in string[string] env=null) const { - // TODO: Use serverRunner instead of venv - auto res = _project.venv.run( - scriptPath, - options, - _project.project_root, - getServerEnv(env)); - - return res; - } - - /// ditto - auto run(in string[] options...) const { - return run(options, null); - } - - /** Run server with provided options - * - * In case of non-zero exit code error will be raised. - * - * Params: - * options = list of options to pass to the server - * env = extra environment variables to pass to the server - **/ - auto runE(in string[] options, in string[string] env=null) const { - auto result = run(options, env).ensureStatus!ServerCommandFailedException(true); - return result; - } - - /// ditto - auto runE(in string[] options...) const { - return runE(options, null); - } - /** Check if the Odoo server is running or not * **/ @@ -324,7 +284,7 @@ struct OdooServer { **/ void stopOdoodServer() const { import core.sys.posix.signal: kill, SIGTERM; - import core.stdc.errno: ESRCH; + import core.stdc.errno: errno, ESRCH; import std.exception: ErrnoException; info("Stopping odoo server..."); From e4d799ef2108108436482ab08f55c5e38c21a108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Thu, 26 Sep 2024 19:48:29 +0300 Subject: [PATCH 21/51] [FIX][Tests] Adapt tests to avoid using server.run. Use server.getServerRunner instead --- subpackages/lib/source/odood/lib/server/server.d | 2 ++ tests/basic.d | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/subpackages/lib/source/odood/lib/server/server.d b/subpackages/lib/source/odood/lib/server/server.d index c8794e8f..961b45ec 100644 --- a/subpackages/lib/source/odood/lib/server/server.d +++ b/subpackages/lib/source/odood/lib/server/server.d @@ -195,6 +195,8 @@ struct OdooServer { } if (_project.odoo.pidfile.exists) { + // At this point it is already checked that server is not running, + // thus it is safe to delete stale pid file. tracef("Removing pidfile %s before server starts...", _project.odoo.pidfile); _project.odoo.pidfile.remove(); } diff --git a/tests/basic.d b/tests/basic.d index 7c146942..3e69e63c 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -494,7 +494,7 @@ unittest { testServerManagement(project); // Test that server initialization works fine - project.server.run("--stop-after-init", "--no-http"); + project.server.getServerRunner("--stop-after-init", "--no-http").execute; // Reinstall Odoo to version 15 project.reinstallOdoo(OdooSerie(15), true); @@ -505,7 +505,7 @@ unittest { project.config_path.shouldEqual(temp_path.join("odood.yml")); // Test that server initialization works fine - project.server.run("--stop-after-init", "--no-http"); + project.server.getServerRunner("--stop-after-init", "--no-http").execute; // Run basic tests project.runBasicTests; From 2e2340b40f95070a4b8558230767e7937516fe87 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Fri, 27 Sep 2024 20:38:28 +0300 Subject: [PATCH 22/51] [REF] Changed odood server run command, to use execv and pass all unparsed arguments directly to Odoo. --- CHANGELOG.md | 15 ++++++++++ .../cli/source/odood/cli/commands/odoo.d | 19 ------------ .../cli/source/odood/cli/commands/server.d | 30 +++++++++++++++---- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c8a4f98..ec7edf80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,21 @@ - `odood pre-commit init` - `odood pre-commit set-up` - `odood pre-commit run` +- Change command `odood server run`. Command uses `execv` to run Odoo, + thus, Odoo process will replace Odood process. Thus, option `--detach` + is not available here. If you want to start Odoo in background, then + `odood server start` command exists. Instead, this command (`odood server run`) + is designed to run Odoo with provided args in same way as you run Odoo binary directly. + For example, following command + `odood server run -- -d my_database --install=crm --stop-after-init`, + that will install `crm` module, will be translated to `odoo -d my_database --install=crm --stop-after-init`, + that will be ran inside virtualenv of current Odood project. + - Added new option `--ignore-running` that allows to ignore server running. + - Removed option `--detach` as it does not have sense. Use `odood server start` instead. + +### Removed + +- Removed command `odood odoo run`. Use `odood server run` instead. --- diff --git a/subpackages/cli/source/odood/cli/commands/odoo.d b/subpackages/cli/source/odood/cli/commands/odoo.d index 6b8594a6..a136faa4 100644 --- a/subpackages/cli/source/odood/cli/commands/odoo.d +++ b/subpackages/cli/source/odood/cli/commands/odoo.d @@ -27,29 +27,10 @@ class CommandOdooShell: OdoodCommand { } -class CommandOdooRun: OdoodCommand { - this() { - super("run", "Run Odoo. All arguments after '--' will be passed to Odoo."); - } - - public override void execute(ProgramArgs args) { - // TODO: May be merge with server/run? - // Also, add ability to update config before running - // Odoo based on environment variables, that will be useful in case, - // when running in docker. - Project.loadProject.server.getServerRunner() - .addArgs(args.argsRest) - .execv; - } -} - - - class CommandOdoo: OdoodCommand { this() { super("odoo", "Odoo-related utility commands."); this.add(new CommandOdooShell()); - this.add(new CommandOdooRun()); } } diff --git a/subpackages/cli/source/odood/cli/commands/server.d b/subpackages/cli/source/odood/cli/commands/server.d index 21305f55..cda26bf7 100644 --- a/subpackages/cli/source/odood/cli/commands/server.d +++ b/subpackages/cli/source/odood/cli/commands/server.d @@ -5,12 +5,13 @@ private import std.logger; private import std.conv: to; private import std.format: format; private import std.exception: enforce; +private import std.algorithm.searching: canFind, startsWith; private import thepath: Path; private import theprocess: Process; private import commandr: Option, Flag, ProgramArgs; -private import odood.cli.core: OdoodCommand; +private import odood.cli.core: OdoodCommand, OdoodCLIException; private import odood.lib.project: Project; private import odood.utils.odoo.serie: OdooSerie; @@ -18,17 +19,34 @@ private import odood.utils.odoo.serie: OdooSerie; class CommandServerRun: OdoodCommand { this() { super("run", "Run the server."); - this.add(new Flag("d", "detach", "Run the server in background.")); - // TODO: Add ability to run with execv (useful in docker) + this.add(new Flag( + "null", "ignore-running", "Ingore running Odoo instance.")); // TODO: Add ability to update odoo config based on environment, - // that is useful when running inside docker containers + // that is useful when running inside docker containers. + // For example, we can generate new config, and run Odoo + // with newly generated temporary config, instead of rewriting + // existing one. } public override void execute(ProgramArgs args) { auto project = Project.loadProject; - project.server.spawn(args.flag("detach")); - } + auto runner = project.server.getServerRunner(); + if (args.flag("ignore-running")) { + // if no --pidfile option specified, enforce no pidfile. + // This is needed to avoid messing up pid of running app. + if (!args.argsRest.canFind!((e) => e.startsWith("--pidfile"))) + runner.addArgs("--pidfile="); + } else { + enforce!OdoodCLIException( + !project.server.isRunning, + "Odoo server already running!"); + } + + runner.addArgs(args.argsRest); + debug tracef("Running Odoo: %s", runner); + runner.execv; + } } From b706285d6991172df1415fdb605dba25cf46df95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=BE=20=D0=9A=D0=B0=D1=82?= =?UTF-8?q?=D1=8E=D1=85=D0=B0?= Date: Tue, 8 Oct 2024 18:03:26 +0300 Subject: [PATCH 23/51] [CI] Add tests for Odoo 18 --- .github/workflows/test-deployments.yml | 1 + tests/basic.d | 49 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/.github/workflows/test-deployments.yml b/.github/workflows/test-deployments.yml index 20d9032c..42e267e9 100644 --- a/.github/workflows/test-deployments.yml +++ b/.github/workflows/test-deployments.yml @@ -52,6 +52,7 @@ jobs: - "ubuntu:23.04" - "ubuntu:24.04" odoo_version: + - "18.0" - "17.0" - "16.0" runs-on: ubuntu-22.04 diff --git a/tests/basic.d b/tests/basic.d index 3e69e63c..758c9c05 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -244,6 +244,55 @@ void runBasicTests(in Project project) { // TODO: Complete the test } +@("Basic Test Odoo 18") +unittest { + auto temp_path = createTempPath( + environment.get("TEST_ODOO_TEMP", std.file.tempDir), + "tmp-odood-18", + ); + scope(exit) temp_path.remove(); + + // Create database use for odoo 17 instance + createDbUser("odood18test", "odoo"); + + auto project = new Project(temp_path, OdooSerie(18)); + auto odoo_conf = OdooConfigBuilder(project) + .setDBConfig( + environment.get("POSTGRES_HOST", "localhost"), + environment.get("POSTGRES_PORT", "5432"), + "odood18test", + "odoo") + .setHttp("localhost", "18069") + .result(); + project.initialize(odoo_conf); + project.save(); + + // Test created project + project.project_root.shouldEqual(temp_path); + project.odoo.serie.shouldEqual(OdooSerie(18)); + project.config_path.shouldEqual(temp_path.join("odood.yml")); + + // Run basic tests + //project.runBasicTests; + + /* + * TODO: Currently, because some addons used in tests are not ported to 17, + * we do not test addons management. But later, when that addons ported + * we have to chage this and run tests for addons management for Odoo 17 + */ + + // Test server management + testServerManagement(project); + + // Test LOdoo Database operations + testDatabaseManagement(project); + + // Test basic addons management + //testAddonsManagementBasic(project); + + // Test running scripts + testRunningScripts(project); +} @("Basic Test Odoo 17") unittest { From c8dbfa4defb93299238b13edca88265f5486727e Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 14 Oct 2024 18:31:40 +0300 Subject: [PATCH 24/51] Updated suitabe python versions --- CHANGELOG.md | 1 + subpackages/lib/source/odood/lib/odoo/python.d | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec7edf80..f90ce9ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - New command `odood odoo run` that allows to run Odoo itself. - New command `odood deploy` that could be used to deploy production-ready Odoo instance. +- Added experimental support for Odoo 18 ### Changed diff --git a/subpackages/lib/source/odood/lib/odoo/python.d b/subpackages/lib/source/odood/lib/odoo/python.d index af936616..54eef747 100644 --- a/subpackages/lib/source/odood/lib/odoo/python.d +++ b/subpackages/lib/source/odood/lib/odoo/python.d @@ -33,14 +33,16 @@ string suggestPythonVersion(in Project project) { if (project.odoo.serie == OdooSerie(12)) return "3.7.17"; if (project.odoo.serie == OdooSerie(13)) - return "3.8.17"; + return "3.8.20"; if (project.odoo.serie == OdooSerie(14)) - return "3.8.17"; + return "3.8.20"; if (project.odoo.serie == OdooSerie(15)) - return "3.8.17"; + return "3.8.20"; if (project.odoo.serie == OdooSerie(16)) - return "3.8.17"; + return "3.8.20"; if (project.odoo.serie == OdooSerie(17)) - return "3.10.13"; - return "3.8.17"; + return "3.10.15"; + if (project.odoo.serie == OdooSerie(18)) + return "3.10.15"; + return "3.8.20"; } From 62c40fa04b4fe0d1ba8a0cbbfea8d0aca3e59c34 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 17 Oct 2024 17:47:42 +0300 Subject: [PATCH 25/51] [FIX] tests for Odoo 18 --- subpackages/cli/source/odood/cli/commands/server.d | 2 +- subpackages/lib/source/odood/lib/odoo/test.d | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/subpackages/cli/source/odood/cli/commands/server.d b/subpackages/cli/source/odood/cli/commands/server.d index cda26bf7..6667c156 100644 --- a/subpackages/cli/source/odood/cli/commands/server.d +++ b/subpackages/cli/source/odood/cli/commands/server.d @@ -20,7 +20,7 @@ class CommandServerRun: OdoodCommand { this() { super("run", "Run the server."); this.add(new Flag( - "null", "ignore-running", "Ingore running Odoo instance.")); + null, "ignore-running", "Ingore running Odoo instance.")); // TODO: Add ability to update odoo config based on environment, // that is useful when running inside docker containers. // For example, we can generate new config, and run Odoo diff --git a/subpackages/lib/source/odood/lib/odoo/test.d b/subpackages/lib/source/odood/lib/odoo/test.d index 47e61862..40fbc731 100644 --- a/subpackages/lib/source/odood/lib/odoo/test.d +++ b/subpackages/lib/source/odood/lib/odoo/test.d @@ -520,7 +520,9 @@ struct OdooTestRunner { "--log-level=warn", "--stop-after-init", "--workers=0", - "--longpolling-port=%s".format(ODOO_TEST_LONGPOLLING_PORT), + _project.odoo.serie < OdooSerie(16) ? + "--longpolling-port=%s".format(ODOO_TEST_LONGPOLLING_PORT) : + "--gevent-port=%s".format(ODOO_TEST_LONGPOLLING_PORT), opt_http_port, "--database=%s".format(_test_db_name), ] From 5ee95a8d027b6e81be6ea70bfe84a2bf826b6d4e Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 17 Oct 2024 17:54:17 +0300 Subject: [PATCH 26/51] Update readme and changelog --- CHANGELOG.md | 7 +------ README.md | 7 ++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f90ce9ca..409fee23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,7 @@ ### Added -- New command `odood odoo run` that allows to run Odoo itself. -- New command `odood deploy` that could be used to deploy production-ready Odoo instance. +- New experimental command `odood deploy` that could be used to deploy production-ready Odoo instance. - Added experimental support for Odoo 18 ### Changed @@ -27,10 +26,6 @@ - Added new option `--ignore-running` that allows to ignore server running. - Removed option `--detach` as it does not have sense. Use `odood server start` instead. -### Removed - -- Removed command `odood odoo run`. Use `odood server run` instead. - --- ## Release 0.1.0 (2024-08-15) diff --git a/README.md b/README.md index 786f15e2..cf3e9898 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ project with Odood is to run command `odood discover odoo-helper` somewhere insi ## Quick start -Use following command to create new local odoo instance: +Use following command to create new local (development) odoo instance: ```bash odood init -v 17 -i odoo-17.0 --db-user=odoo17 --db-password=odoo --http-port=17069 --create-db-user @@ -78,6 +78,11 @@ odood init -v 17 -i odoo-17.0 --db-user=odoo17 --db-password=odoo --http-port=17 This command will create new virtual environment for Odoo and install odoo there. Also, this command will automatically create database user for this Odoo instance. +For production installations, you can use command `odood deploy` that will +deploy Odoo of specified version to machine where this command is running. +For example: `odood deploy -v 17 --supervisor=systemd --local-postgres --enable-logrotate` +But this command is still experimental. + Next, change current working directory to directory where we installed Odoo: ```bash From eb3e2e6be30ab44af4d8c98cb66e5a579023cf08 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 21 Oct 2024 16:13:54 +0300 Subject: [PATCH 27/51] Update dependencies --- dub.selections.json | 2 +- subpackages/cli/dub.selections.json | 2 +- subpackages/lib/dub.selections.json | 2 +- subpackages/utils/dub.selections.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dub.selections.json b/dub.selections.json index 5f0cb09e..9a5ca281 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -16,7 +16,7 @@ "silly": "1.1.1", "tabletool": "0.5.0", "thepath": "2.0.0", - "theprocess": "0.0.5", + "theprocess": "0.0.6", "tinyendian": "0.2.0", "unit-threaded": "2.1.9", "zipper": "0.0.5" diff --git a/subpackages/cli/dub.selections.json b/subpackages/cli/dub.selections.json index cdca8ed3..080aaeee 100644 --- a/subpackages/cli/dub.selections.json +++ b/subpackages/cli/dub.selections.json @@ -16,7 +16,7 @@ "requests": "2.1.3", "tabletool": "0.5.0", "thepath": "2.0.0", - "theprocess": "0.0.5", + "theprocess": "0.0.6", "tinyendian": "0.2.0", "unit-threaded": "2.1.9", "zipper": "0.0.5" diff --git a/subpackages/lib/dub.selections.json b/subpackages/lib/dub.selections.json index dbfcd00c..849548c2 100644 --- a/subpackages/lib/dub.selections.json +++ b/subpackages/lib/dub.selections.json @@ -12,7 +12,7 @@ "prettyprint": "1.0.9", "requests": "2.1.3", "thepath": "2.0.0", - "theprocess": "0.0.5", + "theprocess": "0.0.6", "tinyendian": "0.2.0", "unit-threaded": "2.2.0", "zipper": "0.0.5" diff --git a/subpackages/utils/dub.selections.json b/subpackages/utils/dub.selections.json index e1b04101..44250524 100644 --- a/subpackages/utils/dub.selections.json +++ b/subpackages/utils/dub.selections.json @@ -9,7 +9,7 @@ "prettyprint": "1.0.9", "requests": "2.1.3", "thepath": "2.0.0", - "theprocess": "0.0.5", + "theprocess": "0.0.6", "unit-threaded": "2.2.0", "zipper": "0.0.5" } From 140719ef2e1011fb9e770549c00a8b6cf52c96c4 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 21 Oct 2024 16:23:12 +0300 Subject: [PATCH 28/51] Updated readme --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index cf3e9898..de65f4ee 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,22 @@ Following features currently implemented: - [x] Linters - use pre-commit and per-repo configurations, instead of directly running linters +## Supported Odoo versions + +- Odoo 7.0 (partial) +- Odoo 8.0 (best efforts) +- Odoo 9.0 (best efforts) +- Odoo 10.0 (best efforts) +- Odoo 11.0 (best efforts) +- Odoo 12.0 (tested) +- Odoo 13.0 (tested) +- Odoo 14.0 (tested) +- Odoo 15.0 (tested) +- Odoo 16.0 (tested) +- Odoo 17.0 (tested) +- Odoo 18.0 (experimental) + + ## Installation (as Debian Package) This is the recommended way to install Odood. @@ -123,6 +139,21 @@ See help for this command for more info: odood addons --help ``` +It is possible to easily add repositories with third-party addons to odood projects. +To do this, following command could be used + +```bash +odood repo add --help +``` + +For example, if you want to add [crnd-inc/generic-addons](https://github.com/crnd-inc/generic-addons) +you can run following command: + +```bash +odood repo add --github crnd-inc/generic-addons +``` + + ## Level up your service quality Level up your service quality with [Service Desk](https://crnd.pro/solutions/service-desk) / [ITSM](https://crnd.pro/itsm) solution by [CR&D](https://crnd.pro/). From d8034180f72ded9ecd87f213c163bff9f11251bd Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 21 Oct 2024 18:42:35 +0300 Subject: [PATCH 29/51] [REF] move odood.utils.git to subpackage odood:git --- dub.sdl | 2 ++ subpackages/git/.gitignore | 1 + subpackages/git/dub.sdl | 25 +++++++++++++++++++ subpackages/git/dub.selections.json | 11 ++++++++ .../utils => git/source/odood}/git/package.d | 7 +++--- .../source/odood}/git/repository.d | 3 ++- .../utils => git/source/odood}/git/url.d | 3 ++- subpackages/lib/dub.sdl | 1 + .../lib/source/odood/lib/addons/manager.d | 2 +- .../lib/source/odood/lib/addons/repository.d | 2 +- .../lib/source/odood/lib/install/odoo.d | 2 +- .../lib/source/odood/lib/project/project.d | 2 +- 12 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 subpackages/git/.gitignore create mode 100644 subpackages/git/dub.sdl create mode 100644 subpackages/git/dub.selections.json rename subpackages/{utils/source/odood/utils => git/source/odood}/git/package.d (92%) rename subpackages/{utils/source/odood/utils => git/source/odood}/git/repository.d (98%) rename subpackages/{utils/source/odood/utils => git/source/odood}/git/url.d (99%) diff --git a/dub.sdl b/dub.sdl index ea6097a9..69625fc8 100644 --- a/dub.sdl +++ b/dub.sdl @@ -7,11 +7,13 @@ license "MPL-2.0" dependency ":exception" version="*" dependency ":tipy" version="*" dependency ":utils" version="*" +dependency ":git" version="*" dependency ":lib" version="*" dependency ":cli" version="*" subPackage "./subpackages/exception" subPackage "./subpackages/tipy" subPackage "./subpackages/utils" +subPackage "./subpackages/git" subPackage "./subpackages/lib" subPackage "./subpackages/cli" diff --git a/subpackages/git/.gitignore b/subpackages/git/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/subpackages/git/.gitignore @@ -0,0 +1 @@ +/build diff --git a/subpackages/git/dub.sdl b/subpackages/git/dub.sdl new file mode 100644 index 00000000..46d22880 --- /dev/null +++ b/subpackages/git/dub.sdl @@ -0,0 +1,25 @@ +name "git" +description "Odood wrapper for Git CLI" +authors "Dmytro Katyukha" +copyright "Copyright © 2022-2023, Dmytro Katyukha" +license "MPL-2.0" + +dependency "thepath" version=">=1.2.0" +dependency "theprocess" version=">=0.0.5" + +targetPath "build" +targetType "library" + +dependency "odood:exception" path="../../" + +configuration "library" { +} + +configuration "sourceLibrary" { + targetType "sourceLibrary" +} + +configuration "unittest" { + dependency "unit-threaded:assertions" version=">=2.0.0" +} + diff --git a/subpackages/git/dub.selections.json b/subpackages/git/dub.selections.json new file mode 100644 index 00000000..cdd3c8d2 --- /dev/null +++ b/subpackages/git/dub.selections.json @@ -0,0 +1,11 @@ +{ + "fileVersion": 1, + "versions": { + "dshould": "1.7.2", + "odood": {"path":"../../"}, + "prettyprint": "1.0.9", + "thepath": "2.0.0", + "theprocess": "0.0.6", + "unit-threaded": "2.2.0" + } +} diff --git a/subpackages/utils/source/odood/utils/git/package.d b/subpackages/git/source/odood/git/package.d similarity index 92% rename from subpackages/utils/source/odood/utils/git/package.d rename to subpackages/git/source/odood/git/package.d index 8c820c3b..602943d0 100644 --- a/subpackages/utils/source/odood/utils/git/package.d +++ b/subpackages/git/source/odood/git/package.d @@ -1,4 +1,4 @@ -module odood.utils.git; +module odood.git; private import std.logger: infof; private import std.exception: enforce; @@ -9,8 +9,8 @@ private import thepath: Path; private import odood.exception: OdoodException; private import theprocess: Process; -public import odood.utils.git.url: GitURL; -public import odood.utils.git.repository: GitRepository; +public import odood.git.url: GitURL; +public import odood.git.repository: GitRepository; /// Parse git url for further processing @@ -59,3 +59,4 @@ bool isGitRepo(in Path path) { return false; } + diff --git a/subpackages/utils/source/odood/utils/git/repository.d b/subpackages/git/source/odood/git/repository.d similarity index 98% rename from subpackages/utils/source/odood/utils/git/repository.d rename to subpackages/git/source/odood/git/repository.d index d5976548..f9063176 100644 --- a/subpackages/utils/source/odood/utils/git/repository.d +++ b/subpackages/git/source/odood/git/repository.d @@ -1,4 +1,4 @@ -module odood.utils.git.repository; +module odood.git.repository; private import std.typecons: Nullable, nullable; private import std.string: chompPrefix, strip; @@ -88,3 +88,4 @@ class GitRepository { } } + diff --git a/subpackages/utils/source/odood/utils/git/url.d b/subpackages/git/source/odood/git/url.d similarity index 99% rename from subpackages/utils/source/odood/utils/git/url.d rename to subpackages/git/source/odood/git/url.d index 2805c71e..4b6201c6 100644 --- a/subpackages/utils/source/odood/utils/git/url.d +++ b/subpackages/git/source/odood/git/url.d @@ -1,4 +1,4 @@ -module odood.utils.git.url; +module odood.git.url; private import std.logger: infof; private import std.regex: ctRegex, matchFirst; @@ -261,3 +261,4 @@ unittest { toUrl.shouldEqual("ssh://git@gitlab.crnd.pro/crnd/crnd-account"); } } + diff --git a/subpackages/lib/dub.sdl b/subpackages/lib/dub.sdl index beec6eda..8d225894 100644 --- a/subpackages/lib/dub.sdl +++ b/subpackages/lib/dub.sdl @@ -12,6 +12,7 @@ dependency "dpq" version=">=0.11.6" targetPath "build" targetType "library" +dependency "odood:git" path="../../" dependency "odood:utils" path="../../" dependency "odood:exception" path="../../" diff --git a/subpackages/lib/source/odood/lib/addons/manager.d b/subpackages/lib/source/odood/lib/addons/manager.d index bb82744e..1dfcd25e 100644 --- a/subpackages/lib/source/odood/lib/addons/manager.d +++ b/subpackages/lib/source/odood/lib/addons/manager.d @@ -20,7 +20,7 @@ private import odood.utils.addons.odoo_requirements: parseOdooRequirements, OdooRequirementsLineType; private import odood.lib.addons.repository: AddonRepository; private import odood.utils: download; -private import odood.utils.git: parseGitURL, gitClone; +private import odood.git: parseGitURL, gitClone; private import odood.exception: OdoodException; /// Install python dependencies requirements.txt by default diff --git a/subpackages/lib/source/odood/lib/addons/repository.d b/subpackages/lib/source/odood/lib/addons/repository.d index 457f132e..b8ea203f 100644 --- a/subpackages/lib/source/odood/lib/addons/repository.d +++ b/subpackages/lib/source/odood/lib/addons/repository.d @@ -6,7 +6,7 @@ private import thepath: Path; private import odood.lib.project: Project; private import odood.exception: OdoodException; -private import odood.utils.git: GitRepository; +private import odood.git: GitRepository; class AddonRepository : GitRepository{ diff --git a/subpackages/lib/source/odood/lib/install/odoo.d b/subpackages/lib/source/odood/lib/install/odoo.d index f09f55c8..0d76ad20 100644 --- a/subpackages/lib/source/odood/lib/install/odoo.d +++ b/subpackages/lib/source/odood/lib/install/odoo.d @@ -15,7 +15,7 @@ private import odood.exception: OdoodException; private import odood.lib.project: Project; private import odood.utils.odoo.serie: OdooSerie; -private import odood.utils.git; +private import odood.git; private import odood.utils; private import odood.utils.versioned: Version; diff --git a/subpackages/lib/source/odood/lib/project/project.d b/subpackages/lib/source/odood/lib/project/project.d index 48d5e19f..87b90090 100644 --- a/subpackages/lib/source/odood/lib/project/project.d +++ b/subpackages/lib/source/odood/lib/project/project.d @@ -27,7 +27,7 @@ public import odood.lib.project.config: ProjectConfigOdoo, ProjectConfigDirectories, DEFAULT_ODOO_REPO; private import odood.utils.odoo.serie: OdooSerie; -private import odood.utils.git: isGitRepo; +private import odood.git: isGitRepo; private import odood.utils: generateRandomString; From 4de8240c19aab10b2c99b42d15e525792655ed49 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 21 Oct 2024 19:12:03 +0300 Subject: [PATCH 30/51] [REF] Move git operations to odood:git package for code reusability --- subpackages/git/source/odood/git/package.d | 3 +- subpackages/git/source/odood/git/repository.d | 50 ++++++++++++++----- .../lib/source/odood/lib/addons/manager.d | 4 +- .../lib/source/odood/lib/addons/repository.d | 6 +++ .../lib/source/odood/lib/project/project.d | 21 +++----- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/subpackages/git/source/odood/git/package.d b/subpackages/git/source/odood/git/package.d index 602943d0..84468613 100644 --- a/subpackages/git/source/odood/git/package.d +++ b/subpackages/git/source/odood/git/package.d @@ -19,7 +19,7 @@ GitURL parseGitURL(in string url) { } /// Clone git repository to provided destination directory -void gitClone( +GitRepository gitClone( in GitURL repo, in Path dest, in string branch, @@ -41,6 +41,7 @@ void gitClone( proc.addArgs("--single-branch"); proc.addArgs(repo.applyCIRewrites.toUrl, dest.toString); proc.execute().ensureOk(true); + return new GitRepository(dest); } diff --git a/subpackages/git/source/odood/git/repository.d b/subpackages/git/source/odood/git/repository.d index f9063176..70e02613 100644 --- a/subpackages/git/source/odood/git/repository.d +++ b/subpackages/git/source/odood/git/repository.d @@ -25,6 +25,12 @@ class GitRepository { /// Return path for this repo auto path() const => _path; + /// Preconfigured runner for git CLI + protected auto gitCmd() { + return Process("git") + .inWorkDir(_path); + } + /** Find the name of current git branch for this repo. * * Returns: Nullable!string @@ -32,9 +38,8 @@ class GitRepository { * If result is null, then git repository is in detached-head mode. **/ Nullable!string getCurrBranch() { - auto result = Process("git") - .setArgs(["symbolic-ref", "-q", "HEAD"]) - .setWorkDir(_path) + auto result = gitCmd + .withArgs(["symbolic-ref", "-q", "HEAD"]) .setFlag(std.process.Config.Flags.stderrPassThrough) .execute(); if (result.status == 0) @@ -48,9 +53,8 @@ class GitRepository { * SHA1 hash of current commit **/ string getCurrCommit() { - return Process("git") - .setArgs(["rev-parse", "-q", "HEAD"]) - .setWorkDir(_path) + return gitCmd + .withArgs(["rev-parse", "-q", "HEAD"]) .setFlag(std.process.Config.stderrPassThrough) .execute() .ensureStatus(true) @@ -60,18 +64,16 @@ class GitRepository { /** Fetch remote 'origin' **/ void fetchOrigin() { - Process("git") - .setArgs("fetch", "origin") - .setWorkDir(_path) + gitCmd + .withArgs("fetch", "origin") .execute() .ensureStatus(true); } /// ditto void fetchOrigin(in string branch) { - Process("git") + gitCmd .setArgs("fetch", "origin", branch) - .setWorkDir(_path) .execute() .ensureStatus(true); } @@ -79,13 +81,35 @@ class GitRepository { /** Switch repo to specified branch **/ void switchBranchTo(in string branch_name) { - Process("git") + gitCmd .setArgs("checkout", branch_name) - .setWorkDir(_path) .execute() .ensureStatus(true); } + + /** Set annotation tag on current commit in repo + **/ + void setTag(in string tag_name, in string message = null) + in (tag_name.length > 0) { + // TODO: add ability to set tag on specific commit + gitCmd + .withArgs( + "tag", + "-a", tag_name, + "-m", message.length > 0 ? message : tag_name) + .execute() + .ensureOk(true); + } + + /** Pull repository + **/ + void pull() { + gitCmd + .withArgs("pull") + .execute() + .ensureOk(true); + } } diff --git a/subpackages/lib/source/odood/lib/addons/manager.d b/subpackages/lib/source/odood/lib/addons/manager.d index 1dfcd25e..4c370835 100644 --- a/subpackages/lib/source/odood/lib/addons/manager.d +++ b/subpackages/lib/source/odood/lib/addons/manager.d @@ -608,10 +608,8 @@ struct AddonManager { return; } - gitClone(git_url, dest, branch, single_branch); + auto repo = gitClone(git_url, dest, branch, single_branch); - // TODO: Do we need to create instance of repo here? - auto repo = new AddonRepository(_project, dest); link( repo.path, true, // recursive diff --git a/subpackages/lib/source/odood/lib/addons/repository.d b/subpackages/lib/source/odood/lib/addons/repository.d index b8ea203f..b9236fbe 100644 --- a/subpackages/lib/source/odood/lib/addons/repository.d +++ b/subpackages/lib/source/odood/lib/addons/repository.d @@ -9,6 +9,7 @@ private import odood.exception: OdoodException; private import odood.git: GitRepository; +// TODO: Do we need this class? class AddonRepository : GitRepository{ private const Project _project; @@ -19,6 +20,11 @@ class AddonRepository : GitRepository{ _project = project; } + this(in Project project, in GitRepository repo) { + super(repo.path); + _project = project; + } + /** Return Odood project associated with this addons repository **/ auto project() const => _project; diff --git a/subpackages/lib/source/odood/lib/project/project.d b/subpackages/lib/source/odood/lib/project/project.d index 87b90090..6e09ae4c 100644 --- a/subpackages/lib/source/odood/lib/project/project.d +++ b/subpackages/lib/source/odood/lib/project/project.d @@ -27,7 +27,7 @@ public import odood.lib.project.config: ProjectConfigOdoo, ProjectConfigDirectories, DEFAULT_ODOO_REPO; private import odood.utils.odoo.serie: OdooSerie; -private import odood.git: isGitRepo; +private import odood.git: isGitRepo, GitRepository; private import odood.utils: generateRandomString; @@ -424,19 +424,12 @@ class Project { auto tag_name = "%s-before-update-%s".format( this.odoo.serie, dt_string); - Process("git") - .withArgs( - "tag", - "-a", tag_name, - "-m", "Save before odoo update (%s)".format(dt_string)) - .inWorkDir(this.odoo.path) - .execute() - .ensureOk(true); - Process("git") - .withArgs("pull") - .inWorkDir(this.odoo.path) - .execute() - .ensureOk(true); + auto repo = new GitRepository(this.odoo.path); + repo.setTag( + tag_name, + "Save before odoo update (%s)".format(dt_string)); + repo.pull(); + break; } this.installOdoo(); From cd47634d3ff9dfa386bafd2bde62fe36ab2638cb Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 21 Oct 2024 20:34:45 +0300 Subject: [PATCH 31/51] Minor improvements to git subpackage --- subpackages/git/source/odood/git/package.d | 17 +++++++++++++++++ subpackages/git/source/odood/git/repository.d | 9 ++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/subpackages/git/source/odood/git/package.d b/subpackages/git/source/odood/git/package.d index 84468613..9af071a4 100644 --- a/subpackages/git/source/odood/git/package.d +++ b/subpackages/git/source/odood/git/package.d @@ -3,6 +3,7 @@ module odood.git; private import std.logger: infof; private import std.exception: enforce; private import std.format: format; +private import std.string: strip; private import thepath: Path; @@ -61,3 +62,19 @@ bool isGitRepo(in Path path) { return false; } +/** Returns absolute path to repository root directory. + + Parametrs: + path = any path inside repository + **/ +Path getGitTopLevel(in Path path) { + return Path( + Process("git") + .inWorkDir(path) + .withArgs("rev-parse", "--show-toplevel") + .execute + .ensureOk(true) + .output + .strip + ); +} diff --git a/subpackages/git/source/odood/git/repository.d b/subpackages/git/source/odood/git/repository.d index 70e02613..e5220ccc 100644 --- a/subpackages/git/source/odood/git/repository.d +++ b/subpackages/git/source/odood/git/repository.d @@ -8,6 +8,7 @@ private import thepath: Path; private import odood.exception: OdoodException; private import theprocess; +private import odood.git: getGitTopLevel; /** Simple class to manage git repositories @@ -18,15 +19,17 @@ class GitRepository { @disable this(); this(in Path path) { - // TODO: automatically handle root path for the repo? - _path = path; + if (path.join(".git").exists) + _path = path; + else + _path = getGitTopLevel(path); } /// Return path for this repo auto path() const => _path; /// Preconfigured runner for git CLI - protected auto gitCmd() { + protected auto gitCmd() const { return Process("git") .inWorkDir(_path); } From 30b6eff34d4939a8c7ca54579240af7a74f1d59f Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 21 Oct 2024 21:49:57 +0300 Subject: [PATCH 32/51] Add ability to fix series in addons --- CHANGELOG.md | 1 + .../source/odood/cli/commands/repository.d | 24 +++++++++- subpackages/lib/source/odood/lib/odoo/utils.d | 47 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 409fee23..5cbd853f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - New experimental command `odood deploy` that could be used to deploy production-ready Odoo instance. - Added experimental support for Odoo 18 +- Added new command `odood repo fix-series` that allows to set series for all modules in repo to project's serie. ### Changed diff --git a/subpackages/cli/source/odood/cli/commands/repository.d b/subpackages/cli/source/odood/cli/commands/repository.d index 73831fa3..f1b8d386 100644 --- a/subpackages/cli/source/odood/cli/commands/repository.d +++ b/subpackages/cli/source/odood/cli/commands/repository.d @@ -8,7 +8,7 @@ private import thepath: Path; private import odood.cli.core: OdoodCommand; private import odood.lib.project: Project; -private import odood.lib.odoo.utils: fixVersionConflict; +private import odood.lib.odoo.utils: fixVersionConflict, updateManifestSerie; class CommandRepositoryAdd: OdoodCommand { @@ -88,11 +88,33 @@ class CommandRepositoryFixVersionConflict: OdoodCommand { } +class CommandRepositoryFixSerie: OdoodCommand { + this() { + super( + "fix-series", + "Fix series in manifests of addons in this repo. Set series to project's serie"); + this.add(new Argument( + "path", "Path to repository to fix conflicts in.").optional()); + } + + public override void execute(ProgramArgs args) { + auto project = Project.loadProject; + + auto repo = project.addons.getRepo( + args.arg("path") ? Path(args.arg("path")) : Path.current); + foreach(addon; repo.addons) + addon.path.join("__manifest__.py").updateManifestSerie( + project.odoo.serie); + } +} + + class CommandRepository: OdoodCommand { this() { super("repo", "Manage git repositories."); this.add(new CommandRepositoryAdd()); this.add(new CommandRepositoryFixVersionConflict()); + this.add(new CommandRepositoryFixSerie()); } } diff --git a/subpackages/lib/source/odood/lib/odoo/utils.d b/subpackages/lib/source/odood/lib/odoo/utils.d index 4590f80a..4393e179 100644 --- a/subpackages/lib/source/odood/lib/odoo/utils.d +++ b/subpackages/lib/source/odood/lib/odoo/utils.d @@ -21,6 +21,9 @@ private auto immutable RE_VERSION_CONFLICT = ctRegex!( `(?P\s+["']version["']:\s)(?P["'])(?P\d+\.\d+\.\d+\.\d+\.\d+)["'],\n` ~ `>>>>>>> .*\n`, "m"); +private auto immutable RE_MANIFEST_SERIE_VERSION = ctRegex!( + `^(?P\s+["']version["']:\s["'])(?P\d+\.\d+\.\d+\.\d+\.\d+)(?P["'],\s*(#.*)?)$`, "m"); + /// Resolve version conflict in provided manifest content. string fixVersionConflictImpl(in string manifest_content, in OdooSerie serie) { @@ -78,3 +81,47 @@ void fixVersionConflict(in Path manifest_path, in OdooSerie serie) { .fixVersionConflictImpl(serie); manifest_path.writeFile(manifest_content); } + +/// Update Odoo serie in manifest to specified. +string updateManifestSerieImpl(in string manifest_content, in OdooSerie serie) { + return manifest_content.replaceAll!((Captures!(string) captures) { + const OdooAddonVersion new_version = OdooAddonVersion(captures["addonversion"]) + .ensureIsStandard.withSerie(serie); + + // TODO: find better way. Check if head and change versions are valid + assert(new_version.isStandard, "New version is not valid!"); + + return "%s%s%s".format( + captures["verprefix"], + new_version.toString, + captures["versuffix"], + ); + })(RE_MANIFEST_SERIE_VERSION); +} + +unittest { + import unit_threaded.assertions; + string manifest_content = `{ + 'name': "Bureaucrat Helpdesk Pro [Obsolete]", + 'author': "Center of Research and Development", + 'website': "https://crnd.pro", + 'version': '16.0.1.10.0', + 'category': 'Helpdesk', +}`; + + manifest_content.updateManifestSerieImpl(OdooSerie(17)).shouldEqual(`{ + 'name': "Bureaucrat Helpdesk Pro [Obsolete]", + 'author': "Center of Research and Development", + 'website': "https://crnd.pro", + 'version': '17.0.1.10.0', + 'category': 'Helpdesk', +}`); +} + +/// Update serie in manifest +void updateManifestSerie(in Path manifest_path, in OdooSerie serie) { + infof("Updating serie in manifest: %s", manifest_path); + string manifest_content = manifest_path.readFileText() + .updateManifestSerieImpl(serie); + manifest_path.writeFile(manifest_content); +} From 7b1d057bd46cdea9c88cf18fa71aeee3d213b34c Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Wed, 23 Oct 2024 13:27:22 +0300 Subject: [PATCH 33/51] Add --log-to-stderr to Odood deploy command --- subpackages/cli/source/odood/cli/commands/deploy.d | 6 ++++++ subpackages/lib/source/odood/lib/deploy/config.d | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/subpackages/cli/source/odood/cli/commands/deploy.d b/subpackages/cli/source/odood/cli/commands/deploy.d index 1c9e5c1a..7cb17e32 100644 --- a/subpackages/cli/source/odood/cli/commands/deploy.d +++ b/subpackages/cli/source/odood/cli/commands/deploy.d @@ -57,6 +57,9 @@ class CommandDeploy: OdoodCommand { null, "supervisor", "What superwisor to use for deployment.") .defaultValue("systemd") .acceptsValues(["odood", "init-script", "systemd"])); + + this.add(new Flag( + null, "log-to-stderr", "Log to stderr. Useful when running inside docker.")); } DeployConfig parseDeployOptions(ProgramArgs args) { @@ -109,6 +112,9 @@ class CommandDeploy: OdoodCommand { assert(0, "Not supported supervisor"); } + if (args.flag("log-to-stderr")) + config.odoo.log_to_stderr = true; + return config; } diff --git a/subpackages/lib/source/odood/lib/deploy/config.d b/subpackages/lib/source/odood/lib/deploy/config.d index 18eeaba0..8f0ebf58 100644 --- a/subpackages/lib/source/odood/lib/deploy/config.d +++ b/subpackages/lib/source/odood/lib/deploy/config.d @@ -46,6 +46,8 @@ struct DeployConfigOdoo { "/", "etc", "systemd", "system", "odoo.service"); Path pidfile = Path("/", "var", "run", "odoo.pid"); + + bool log_to_stderr = false; } struct DeployConfig { @@ -139,6 +141,9 @@ struct DeployConfig { if (odoo.proxy_mode) odoo_config["options"].setKey("proxy_mode", "True"); + if (odoo.log_to_stderr) + odoo_config["options"].removeKey("logfile"); + return odoo_config; } From be05c709a727bdf0cc44a17bf6b5e7cd76514b37 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Wed, 23 Oct 2024 18:26:32 +0300 Subject: [PATCH 34/51] Added experimental docker build --- build_docker.bash | 6 +++ docker/.gitignore | 1 + docker/Dockerfile | 40 +++++++++++++++++++ dub.selections.json | 2 +- subpackages/cli/dub.selections.json | 2 +- .../cli/source/odood/cli/commands/server.d | 23 ++++++++--- subpackages/git/dub.sdl | 2 +- subpackages/git/dub.selections.json | 2 +- subpackages/lib/dub.selections.json | 2 +- .../lib/source/odood/lib/deploy/config.d | 8 ++-- subpackages/utils/dub.sdl | 2 +- subpackages/utils/dub.selections.json | 2 +- 12 files changed, 76 insertions(+), 16 deletions(-) create mode 100755 build_docker.bash create mode 100644 docker/.gitignore create mode 100644 docker/Dockerfile diff --git a/build_docker.bash b/build_docker.bash new file mode 100755 index 00000000..7398b967 --- /dev/null +++ b/build_docker.bash @@ -0,0 +1,6 @@ +#!/bin/bash + + +dub build --d-version OdoodInDocker; +cp ./build/odood ./docker/bin/odood; +(cd ./docker && docker build -t tmp-odood:17 --build-arg ODOO_VERSION=17 --build-arg "ODOOD_DEPENDENCIES=$(cat ../.ci/deps/universal-deb.txt)" .) diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 00000000..5e56e040 --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..e616d07f --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,40 @@ +FROM ubuntu:24.04 + +ARG ODOO_VERSION +ARG ODOOD_DEPENDENCIES + +RUN apt-get update -qq && \ + apt-get install -qqq -y --no-install-recommends --auto-remove \ + locales \ + wget \ + ca-certificates \ + gnupg \ + lsb-release \ + tzdata && \ + locale-gen en_US.UTF-8 && \ + locale-gen en_GB.UTF-8 && \ + update-locale LANG="en_US.UTF-8" && update-locale LANGUAGE="en_US:en" \ + echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ + wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ + apt-key add - && \ + apt-get update -qq && \ + apt-get install -qqq -y --no-install-recommends --auto-remove $ODOOD_DEPENDENCIES && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /root/.cache/pip/* + +# Set corect locale-related environment variables +ENV LANG="en_US.UTF-8" LANGUAGE="en_US:en" LC_ALL="en_US.UTF-8" + +COPY ./bin/odood /usr/bin/odood + +RUN odood deploy -v "$ODOO_VERSION" --supervisor=odood --log-to-stderr + +WORKDIR /opt/odoo + +EXPOSE 8069 +EXPOSE 8071 +EXPOSE 8072 + +VOLUME ["/opt/odoo/data", "/opt/odoo/backups"] + +CMD ["/usr/bin/odood", "server", "run", "--config-from-env"] diff --git a/dub.selections.json b/dub.selections.json index 9a5ca281..f4944869 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -16,7 +16,7 @@ "silly": "1.1.1", "tabletool": "0.5.0", "thepath": "2.0.0", - "theprocess": "0.0.6", + "theprocess": "0.0.7", "tinyendian": "0.2.0", "unit-threaded": "2.1.9", "zipper": "0.0.5" diff --git a/subpackages/cli/dub.selections.json b/subpackages/cli/dub.selections.json index 080aaeee..3471a42f 100644 --- a/subpackages/cli/dub.selections.json +++ b/subpackages/cli/dub.selections.json @@ -16,7 +16,7 @@ "requests": "2.1.3", "tabletool": "0.5.0", "thepath": "2.0.0", - "theprocess": "0.0.6", + "theprocess": "0.0.7", "tinyendian": "0.2.0", "unit-threaded": "2.1.9", "zipper": "0.0.5" diff --git a/subpackages/cli/source/odood/cli/commands/server.d b/subpackages/cli/source/odood/cli/commands/server.d index 6667c156..fa12a349 100644 --- a/subpackages/cli/source/odood/cli/commands/server.d +++ b/subpackages/cli/source/odood/cli/commands/server.d @@ -20,12 +20,11 @@ class CommandServerRun: OdoodCommand { this() { super("run", "Run the server."); this.add(new Flag( - null, "ignore-running", "Ingore running Odoo instance.")); - // TODO: Add ability to update odoo config based on environment, - // that is useful when running inside docker containers. - // For example, we can generate new config, and run Odoo - // with newly generated temporary config, instead of rewriting - // existing one. + null, "ignore-running", "Ingore running Odoo instance. (Do not check/create pidfile).")); + + version(OdoodInDocker) + this.add(new Flag( + null, "config-from-env", "Apply odoo configuration from envrionment")); } public override void execute(ProgramArgs args) { @@ -43,6 +42,18 @@ class CommandServerRun: OdoodCommand { "Odoo server already running!"); } + version(OdoodInDocker) if (args.flag("config-from-env")) { + import std.process: environment; + import std.string: chompPrefix, toLower; + auto config = project.getOdooConfig; + foreach(kv; environment.toAA.byKeyValue) { + string key = kv.key.toLower.chompPrefix("odood_opt_"); + config["options"].setKey(key, kv.value); + } + // In case when we running in Docker, we can just rewrite config + config.save(project.odoo.configfile.toString); + } + runner.addArgs(args.argsRest); debug tracef("Running Odoo: %s", runner); runner.execv; diff --git a/subpackages/git/dub.sdl b/subpackages/git/dub.sdl index 46d22880..884e6086 100644 --- a/subpackages/git/dub.sdl +++ b/subpackages/git/dub.sdl @@ -5,7 +5,7 @@ copyright "Copyright © 2022-2023, Dmytro Katyukha" license "MPL-2.0" dependency "thepath" version=">=1.2.0" -dependency "theprocess" version=">=0.0.5" +dependency "theprocess" version=">=0.0.7" targetPath "build" targetType "library" diff --git a/subpackages/git/dub.selections.json b/subpackages/git/dub.selections.json index cdd3c8d2..1e2fb497 100644 --- a/subpackages/git/dub.selections.json +++ b/subpackages/git/dub.selections.json @@ -5,7 +5,7 @@ "odood": {"path":"../../"}, "prettyprint": "1.0.9", "thepath": "2.0.0", - "theprocess": "0.0.6", + "theprocess": "0.0.7", "unit-threaded": "2.2.0" } } diff --git a/subpackages/lib/dub.selections.json b/subpackages/lib/dub.selections.json index 849548c2..c6ea85ee 100644 --- a/subpackages/lib/dub.selections.json +++ b/subpackages/lib/dub.selections.json @@ -12,7 +12,7 @@ "prettyprint": "1.0.9", "requests": "2.1.3", "thepath": "2.0.0", - "theprocess": "0.0.6", + "theprocess": "0.0.7", "tinyendian": "0.2.0", "unit-threaded": "2.2.0", "zipper": "0.0.5" diff --git a/subpackages/lib/source/odood/lib/deploy/config.d b/subpackages/lib/source/odood/lib/deploy/config.d index 8f0ebf58..47299e4e 100644 --- a/subpackages/lib/source/odood/lib/deploy/config.d +++ b/subpackages/lib/source/odood/lib/deploy/config.d @@ -34,7 +34,7 @@ struct DeployConfigDatabase { struct DeployConfigOdoo { OdooSerie serie; bool proxy_mode=false; - string http_host="localhost"; + string http_host=null; string http_port="8069"; uint workers=0; @@ -129,10 +129,12 @@ struct DeployConfig { odoo_config["options"].setKey("db_password", database.password); if (odoo.serie < OdooSerie(11)) { - odoo_config["options"].setKey("xmlrpc_interface", odoo.http_host); + if (odoo.http_host.length > 0) + odoo_config["options"].setKey("xmlrpc_interface", odoo.http_host); odoo_config["options"].setKey("xmlrpc_port", odoo.http_port); } else { - odoo_config["options"].setKey("http_interface", odoo.http_host); + if (odoo.http_host.length > 0) + odoo_config["options"].setKey("http_interface", odoo.http_host); odoo_config["options"].setKey("http_port", odoo.http_port); } diff --git a/subpackages/utils/dub.sdl b/subpackages/utils/dub.sdl index e8fa9b64..15caa820 100644 --- a/subpackages/utils/dub.sdl +++ b/subpackages/utils/dub.sdl @@ -6,7 +6,7 @@ license "MPL-2.0" dependency "requests" version=">=2.0.0" dependency "thepath" version=">=1.2.0" -dependency "theprocess" version=">=0.0.5" +dependency "theprocess" version=">=0.0.7" dependency "zipper" version="~>0.0.5" targetPath "build" diff --git a/subpackages/utils/dub.selections.json b/subpackages/utils/dub.selections.json index 44250524..f8ec19fc 100644 --- a/subpackages/utils/dub.selections.json +++ b/subpackages/utils/dub.selections.json @@ -9,7 +9,7 @@ "prettyprint": "1.0.9", "requests": "2.1.3", "thepath": "2.0.0", - "theprocess": "0.0.6", + "theprocess": "0.0.7", "unit-threaded": "2.2.0", "zipper": "0.0.5" } From de2d7836b47b9258fb7718b113c130abd54a858d Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Wed, 23 Oct 2024 22:50:16 +0300 Subject: [PATCH 35/51] Add workflow to build and push docker image to gh registry --- .github/workflows/publish-dockerhub.yml | 107 ++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 .github/workflows/publish-dockerhub.yml diff --git a/.github/workflows/publish-dockerhub.yml b/.github/workflows/publish-dockerhub.yml new file mode 100644 index 00000000..ced7d587 --- /dev/null +++ b/.github/workflows/publish-dockerhub.yml @@ -0,0 +1,107 @@ +# +name: Create and publish a Docker image + +# Configures this workflow to run every time new release is published +on: + release: + types: [published] + +# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + ODOOD_DLANG_COMPILER: ldc-1.39.0 + +# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +jobs: + build-ubuntu-20_04: + name: Build Ubuntu:20.04 + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + + - name: Install D compiler + uses: dlang-community/setup-dlang@v1 + with: + compiler: ${{ env.ODOOD_DLANG_COMPILER }} + + - name: Install system dependencies + uses: lyricwulf/abc@v1 + with: + linux: libzip-dev libpq-dev python3-dev + + - name: Build Odood + run: | + dub build -b release -c bash-autocomplete --d-version OdoodInDocker + dub build -b release --d-version OdoodInDocker + + - name: Upload Odood compiled assets + uses: actions/upload-artifact@v3 + with: + name: odood-amd64 + path: | + build/odood + build/odood.bash + + build-and-push-image: + runs-on: ubuntu-latest + # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. + permissions: + contents: read + packages: write + attestations: write + id-token: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: 'Download artifacts for amd64' + uses: actions/download-artifact@v3 + with: + name: odood-amd64 + path: docker/bin/ + + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Prepare debian dependencies dependencies + id: prepare_deb_deps + run: | + echo "universal_deb_deps=$(cat .ci/deps/universal-deb.txt | tr '\n' ',' | sed 's/,$/\n/')" >> $GITHUB_OUTPUT + + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + id: push + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: ./docker + push: true + build-args: + ODOO_VERSION: "17.0" + ODOOD_DEPENDENCIES: ${{ steps.prepare_deb_deps.outputs.universal_deb_deps }} + tags: 17.0-${{ github.ref_name }} # ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)." + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true + From fe037ac904118012d359a667e0c7246733774c10 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 24 Oct 2024 14:35:23 +0300 Subject: [PATCH 36/51] Fix docker build and push --- .github/workflows/publish-dockerhub.yml | 41 +++++++++++++------ docker/Dockerfile | 4 +- docker/bin/.gitkeep | 0 .../odoo-and-db/docker-compose.yml | 39 ++++++++++++++++++ 4 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 docker/bin/.gitkeep create mode 100644 examples/docker-compose/odoo-and-db/docker-compose.yml diff --git a/.github/workflows/publish-dockerhub.yml b/.github/workflows/publish-dockerhub.yml index ced7d587..b09d8905 100644 --- a/.github/workflows/publish-dockerhub.yml +++ b/.github/workflows/publish-dockerhub.yml @@ -3,8 +3,10 @@ name: Create and publish a Docker image # Configures this workflow to run every time new release is published on: - release: - types: [published] + push: + tags: + - 'v*.*.*' + - 'v*.*.*-*' # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: @@ -32,7 +34,6 @@ jobs: - name: Build Odood run: | - dub build -b release -c bash-autocomplete --d-version OdoodInDocker dub build -b release --d-version OdoodInDocker - name: Upload Odood compiled assets @@ -41,7 +42,6 @@ jobs: name: odood-amd64 path: | build/odood - build/odood.bash build-and-push-image: runs-on: ubuntu-latest @@ -51,7 +51,16 @@ jobs: packages: write attestations: write id-token: write - # + needs: + - build-ubuntu-20_04 + strategy: + matrix: + # TODO: Build base image (without Odoo, only with odood itself) and then use it as base for odoo images + odoo_version: + - "15.0" + - "16.0" + - "17.0" + - "18.0" steps: - name: Checkout repository uses: actions/checkout@v4 @@ -62,6 +71,10 @@ jobs: name: odood-amd64 path: docker/bin/ + - name: Make odood executable + run: | + chmod a+x docker/bin/odood + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 @@ -75,12 +88,12 @@ jobs: id: meta uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/odoo/${{ matrix.odoo_version }} - name: Prepare debian dependencies dependencies id: prepare_deb_deps run: | - echo "universal_deb_deps=$(cat .ci/deps/universal-deb.txt | tr '\n' ',' | sed 's/,$/\n/')" >> $GITHUB_OUTPUT + echo "universal_deb_deps=$(cat .ci/deps/universal-deb.txt | tr '\n' ' ')" >> $GITHUB_OUTPUT # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. @@ -91,17 +104,19 @@ jobs: with: context: ./docker push: true - build-args: - ODOO_VERSION: "17.0" - ODOOD_DEPENDENCIES: ${{ steps.prepare_deb_deps.outputs.universal_deb_deps }} - tags: 17.0-${{ github.ref_name }} # ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + build-args: | + ODOO_VERSION=${{ matrix.odoo_version }} + ODOOD_DEPENDENCIES=${{ steps.prepare_deb_deps.outputs.universal_deb_deps }} + tags: ${{ steps.meta.outputs.tags }} + labels: | + ${{ steps.meta.outputs.labels }} + odoo_version=${{ matrix.odoo_version }} # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)." - name: Generate artifact attestation uses: actions/attest-build-provenance@v1 with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}/odoo/${{ matrix.odoo_version }} subject-digest: ${{ steps.push.outputs.digest }} push-to-registry: true diff --git a/docker/Dockerfile b/docker/Dockerfile index e616d07f..2f7faebd 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -27,9 +27,9 @@ ENV LANG="en_US.UTF-8" LANGUAGE="en_US:en" LC_ALL="en_US.UTF-8" COPY ./bin/odood /usr/bin/odood -RUN odood deploy -v "$ODOO_VERSION" --supervisor=odood --log-to-stderr +RUN /usr/bin/odood deploy -v "$ODOO_VERSION" --supervisor=odood --log-to-stderr -WORKDIR /opt/odoo +#WORKDIR /opt/odoo EXPOSE 8069 EXPOSE 8071 diff --git a/docker/bin/.gitkeep b/docker/bin/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/examples/docker-compose/odoo-and-db/docker-compose.yml b/examples/docker-compose/odoo-and-db/docker-compose.yml new file mode 100644 index 00000000..6764364d --- /dev/null +++ b/examples/docker-compose/odoo-and-db/docker-compose.yml @@ -0,0 +1,39 @@ +version: '3' + +volumes: + odood-example-db-data: + odood-example-odoo-data: + +services: + odood-example-db: + image: postgres:15 + container_name: odood-example-db + environment: + - POSTGRES_USER=odoo + - POSTGRES_PASSWORD=odoo-db-pass + + # this is needed to avoid auto-creation of database by postgres itself + # databases must be created by Odoo only + - POSTGRES_DB=postgres + volumes: + - odood-example-db-data:/var/lib/postgresql/data + restart: "no" + + odood-example-odoo: + image: ghcr.io/katyukha/odood/odoo/17.0:latest + container_name: odood-example-odoo + depends_on: + - odood-example-db + environment: + ODOOD_OPT_DB_HOST: odood-example-db + ODOOD_OPT_DB_USER: odoo + ODOOD_OPT_DB_PASSWORD: odoo-db-pass + ODOOD_OPT_ADMIN_PASS: admin + ODOOD_OPT_WORKERS: "1" + ports: + - "8069:8069" + volumes: + - odood-example-odoo-data:/opt/odoo/data + restart: "no" + + From d26bb5cf784de4d8daf9e99e96874cb5bb842b67 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 24 Oct 2024 20:13:25 +0300 Subject: [PATCH 37/51] rename workflow publish-dockerhub to publish-dockerimage --- .../workflows/{publish-dockerhub.yml => publish-dockerimage.yml} | 1 - 1 file changed, 1 deletion(-) rename .github/workflows/{publish-dockerhub.yml => publish-dockerimage.yml} (99%) diff --git a/.github/workflows/publish-dockerhub.yml b/.github/workflows/publish-dockerimage.yml similarity index 99% rename from .github/workflows/publish-dockerhub.yml rename to .github/workflows/publish-dockerimage.yml index b09d8905..52aac3bf 100644 --- a/.github/workflows/publish-dockerhub.yml +++ b/.github/workflows/publish-dockerimage.yml @@ -1,4 +1,3 @@ -# name: Create and publish a Docker image # Configures this workflow to run every time new release is published From f2812083e2b3439976ce0bf978c100dd3e0f5f2a Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 24 Oct 2024 21:30:47 +0300 Subject: [PATCH 38/51] Minor fixes to publish docker images workflow --- .github/workflows/publish-dockerimage.yml | 30 +++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish-dockerimage.yml b/.github/workflows/publish-dockerimage.yml index 52aac3bf..015578bd 100644 --- a/.github/workflows/publish-dockerimage.yml +++ b/.github/workflows/publish-dockerimage.yml @@ -7,13 +7,16 @@ on: - 'v*.*.*' - 'v*.*.*-*' -# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. +# Defines two custom environment variables for the workflow. +# These are used for the Container registry domain, +# and a name for the Docker image that this workflow builds. env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} ODOOD_DLANG_COMPILER: ldc-1.39.0 -# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +# There is a single job in this workflow. +# It's configured to run on the latest available version of Ubuntu. jobs: build-ubuntu-20_04: name: Build Ubuntu:20.04 @@ -42,7 +45,7 @@ jobs: path: | build/odood - build-and-push-image: + build-and-push-images: runs-on: ubuntu-latest # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. permissions: @@ -74,7 +77,9 @@ jobs: run: | chmod a+x docker/bin/odood - # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. + # Uses the `docker/login-action` action to log in to the Container registry + # using the account and password that will publish the packages. + # Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 with: @@ -82,7 +87,10 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) + # to extract tags and labels that will be applied to the specified image. + # The `id` "meta" allows the output of this step to be referenced in a subsequent step. + # The `images` value provides the base name for the tags and labels. - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 @@ -94,8 +102,11 @@ jobs: run: | echo "universal_deb_deps=$(cat .ci/deps/universal-deb.txt | tr '\n' ' ')" >> $GITHUB_OUTPUT - # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. - # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # This step uses the `docker/build-push-action` action to build the image, + # based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. + # For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" + # in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - name: Build and push Docker image id: push @@ -111,7 +122,10 @@ jobs: ${{ steps.meta.outputs.labels }} odoo_version=${{ matrix.odoo_version }} - # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)." + # This step generates an artifact attestation for the image, + # which is an unforgeable statement about where and how it was built. + # It increases supply chain security for people who consume the image. + # For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)." - name: Generate artifact attestation uses: actions/attest-build-provenance@v1 with: From 209db162b6b72dc180154b90f8c55e38d4271042 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 27 Oct 2024 19:11:39 +0200 Subject: [PATCH 39/51] Changed generation of test database name --- CHANGELOG.md | 3 +++ subpackages/lib/source/odood/lib/odoo/test.d | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cbd853f..98c9955b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,9 @@ that will be ran inside virtualenv of current Odood project. - Added new option `--ignore-running` that allows to ignore server running. - Removed option `--detach` as it does not have sense. Use `odood server start` instead. +- Changed generation of default test db name. + Before it was: `odood-odood-test` + Now it will be: `-odood-test` --- diff --git a/subpackages/lib/source/odood/lib/odoo/test.d b/subpackages/lib/source/odood/lib/odoo/test.d index 40fbc731..e3b2fee8 100644 --- a/subpackages/lib/source/odood/lib/odoo/test.d +++ b/subpackages/lib/source/odood/lib/odoo/test.d @@ -37,8 +37,11 @@ private immutable ODOO_TEST_LONGPOLLING_PORT=8272; * Params: * project = project to generate name of test database for. **/ -string generateTestDbName(in Project project) pure { - return "odood%s-odood-test".format(project.odoo.serie.major); +string generateTestDbName(in Project project) { + string prefix = project.getOdooConfig["options"].getKey( + "db_user", + "odood%s".format(project.odoo.serie.major)); + return "%s-odood-test".format(prefix); } From c2b1db4a7ded3a9f1be9b4572dafa4812b679abe Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 27 Oct 2024 21:40:19 +0200 Subject: [PATCH 40/51] Update readme --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/README.md b/README.md index de65f4ee..59554cd7 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,54 @@ you can run following command: odood repo add --github crnd-inc/generic-addons ``` +## Example setup for docker compose + +Odood has prebuilt docker images, that could be used to easily run Odoo powered by Odoo inside docker-based infrastructure. + +See examples directory for more details. + +Example `docker-compose.yml`: + +```yml +version: '3' + +volumes: + odood-example-db-data: + odood-example-odoo-data: + +services: + odood-example-db: + image: postgres:15 + container_name: odood-example-db + environment: + - POSTGRES_USER=odoo + - POSTGRES_PASSWORD=odoo-db-pass + + # this is needed to avoid auto-creation of database by postgres itself + # databases must be created by Odoo only + - POSTGRES_DB=postgres + volumes: + - odood-example-db-data:/var/lib/postgresql/data + restart: "no" + + odood-example-odoo: + image: ghcr.io/katyukha/odood/odoo/17.0:latest + container_name: odood-example-odoo + depends_on: + - odood-example-db + environment: + ODOOD_OPT_DB_HOST: odood-example-db + ODOOD_OPT_DB_USER: odoo + ODOOD_OPT_DB_PASSWORD: odoo-db-pass + ODOOD_OPT_ADMIN_PASS: admin + ODOOD_OPT_WORKERS: "1" + ports: + - "8069:8069" + volumes: + - odood-example-odoo-data:/opt/odoo/data + restart: "no" +``` + ## Level up your service quality From bcc8855352fee9c659fc288728378340d135f75f Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sat, 2 Nov 2024 23:58:46 +0200 Subject: [PATCH 41/51] Added example of running odoo in docker behind traefik --- .../odoo-and-db/docker-compose.yml | 30 +++++++++++++++++-- .../cli/source/odood/cli/commands/addons.d | 17 ++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/examples/docker-compose/odoo-and-db/docker-compose.yml b/examples/docker-compose/odoo-and-db/docker-compose.yml index 6764364d..bcc6ed0c 100644 --- a/examples/docker-compose/odoo-and-db/docker-compose.yml +++ b/examples/docker-compose/odoo-and-db/docker-compose.yml @@ -22,18 +22,42 @@ services: odood-example-odoo: image: ghcr.io/katyukha/odood/odoo/17.0:latest container_name: odood-example-odoo + labels: + - "traefik.enable=true" + - "traefik.http.routers.odoo-route.rule=Host(`localhost`)" + - "traefik.http.routers.odoo-route.service=odoo-service" + - "traefik.http.routers.odoo-route.entrypoints=web" + - "traefik.http.services.odoo-service.loadbalancer.server.port=8069" + - "traefik.http.routers.odoo-ge-route.rule=Host(`localhost`) && Path(`/websocket`)" + - "traefik.http.routers.odoo-ge-route.service=odoo-ge-service" + - "traefik.http.routers.odoo-ge-route.entrypoints=web" + - "traefik.http.services.odoo-ge-service.loadbalancer.server.port=8072" + depends_on: - odood-example-db environment: ODOOD_OPT_DB_HOST: odood-example-db ODOOD_OPT_DB_USER: odoo ODOOD_OPT_DB_PASSWORD: odoo-db-pass - ODOOD_OPT_ADMIN_PASS: admin + ODOOD_OPT_ADMIN_PASSWD: admin ODOOD_OPT_WORKERS: "1" - ports: - - "8069:8069" + ODOOD_OPT_PROXY_MODE: True volumes: - odood-example-odoo-data:/opt/odoo/data restart: "no" + odood-example-traefik: + image: "traefik:v3.2" + container_name: "odood-example-traefik" + command: + #- "--log.level=DEBUG" + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entryPoints.web.address=:80" + ports: + - "80:80" + - "8080:8080" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" diff --git a/subpackages/cli/source/odood/cli/commands/addons.d b/subpackages/cli/source/odood/cli/commands/addons.d index 6323ee4a..44132374 100644 --- a/subpackages/cli/source/odood/cli/commands/addons.d +++ b/subpackages/cli/source/odood/cli/commands/addons.d @@ -583,12 +583,27 @@ class CommandAddonsUninstall: CommandAddonsUpdateInstallUninstall { } +/* TODO: implement command 'autoupdate' with following logic: + * 1. Create mapping {addon_name: version} for all addons available in + * filesystem. + * 2. For each database, check if there are addons on disk that are not + * mentioned in database. If such addons found, + * update list of addons in database. This stage ma fail and its ok. + * This stage needed to ensure that dependencies of modules updated. + * 3. for each database find installed addons that have different + * versions then in addons on disk. And update them + * + * This command should be useful on servers to automatically update server + * if needed. But this will require control over module versions. + */ + + class CommandAddonsAdd: OdoodCommand { this() { super("add", "Add addons to the project"); this.add(new Flag( null, "single-branch", - "Clone repository wihth --single-branch options. " ~ + "Clone repository with --single-branch options. " ~ "This could significantly reduce size of data to be downloaded " ~ "and increase performance.")); this.add(new Flag( From 918bc49a546b952864ebc8f86b51aeaad81ddfb2 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 3 Nov 2024 00:01:47 +0200 Subject: [PATCH 42/51] Fix README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59554cd7..643cc341 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ services: ODOOD_OPT_DB_HOST: odood-example-db ODOOD_OPT_DB_USER: odoo ODOOD_OPT_DB_PASSWORD: odoo-db-pass - ODOOD_OPT_ADMIN_PASS: admin + ODOOD_OPT_ADMIN_PASSWD: admin ODOOD_OPT_WORKERS: "1" ports: - "8069:8069" From 2174c93f3e8c80efb1acf7ed5ac57ae0a35fcd5c Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 10 Nov 2024 18:39:28 +0200 Subject: [PATCH 43/51] Added example of running odoo on localhost with ssl using docker compose and traefik --- .../odoo-and-db-ssl/docker-compose.yml | 73 +++++++++++++++++++ .../odoo-and-db-ssl/traefik/certs/.gitignore | 1 + .../odoo-and-db-ssl/traefik/certs/README.md | 2 + .../odoo-and-db-ssl/traefik/traefik-certs.yml | 4 + 4 files changed, 80 insertions(+) create mode 100644 examples/docker-compose/odoo-and-db-ssl/docker-compose.yml create mode 100644 examples/docker-compose/odoo-and-db-ssl/traefik/certs/.gitignore create mode 100644 examples/docker-compose/odoo-and-db-ssl/traefik/certs/README.md create mode 100644 examples/docker-compose/odoo-and-db-ssl/traefik/traefik-certs.yml diff --git a/examples/docker-compose/odoo-and-db-ssl/docker-compose.yml b/examples/docker-compose/odoo-and-db-ssl/docker-compose.yml new file mode 100644 index 00000000..9cfaf453 --- /dev/null +++ b/examples/docker-compose/odoo-and-db-ssl/docker-compose.yml @@ -0,0 +1,73 @@ +version: '3' + +volumes: + odood-example-ssl-db-data: + odood-example-ssl-odoo-data: + +services: + odood-example-ssl-db: + image: postgres:15 + container_name: odood-example-ssl-db + environment: + - POSTGRES_USER=odoo + - POSTGRES_PASSWORD=odoo-db-pass + + # this is needed to avoid auto-creation of database by postgres itself + # databases must be created by Odoo only + - POSTGRES_DB=postgres + volumes: + - odood-example-ssl-db-data:/var/lib/postgresql/data + restart: "no" + + odood-example-ssl-odoo: + image: ghcr.io/katyukha/odood/odoo/17.0:latest + container_name: odood-example-ssl-odoo + labels: + - "traefik.enable=true" + - "traefik.http.routers.odoo-route.rule=Host(`localhost`)" + - "traefik.http.routers.odoo-route.service=odoo-service" + - "traefik.http.routers.odoo-route.entrypoints=webssl" + - "traefik.http.routers.odoo-route.tls=true" + - "traefik.http.services.odoo-service.loadbalancer.server.port=8069" + - "traefik.http.routers.odoo-ge-route.rule=Host(`localhost`) && Path(`/websocket`)" + - "traefik.http.routers.odoo-ge-route.service=odoo-ge-service" + - "traefik.http.routers.odoo-ge-route.entrypoints=webssl" + - "traefik.http.routers.odoo-ge-route.tls=true" + - "traefik.http.services.odoo-ge-service.loadbalancer.server.port=8072" + + depends_on: + - odood-example-ssl-db + environment: + ODOOD_OPT_DB_HOST: odood-example-ssl-db + ODOOD_OPT_DB_USER: odoo + ODOOD_OPT_DB_PASSWORD: odoo-db-pass + ODOOD_OPT_ADMIN_PASSWD: admin + ODOOD_OPT_WORKERS: "1" + ODOOD_OPT_PROXY_MODE: True + volumes: + - odood-example-ssl-odoo-data:/opt/odoo/data + restart: "no" + + odood-example-ssl-traefik: + image: "traefik:v3.2" + container_name: "odood-example-ssl-traefik" + command: + #- "--log.level=DEBUG" + #- "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--providers.file.filename=/traefik-certs.yml" + - "--entryPoints.web.address=:80" + - "--entryPoints.webssl.address=:443" + - "--entrypoints.web.http.redirections.entrypoint.to=webssl" + - "--entrypoints.web.http.redirections.entrypoint.scheme=https" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "./traefik/traefik-certs.yml:/traefik-certs.yml" + - "./traefik/certs/:/certs/" + - "/var/run/docker.sock:/var/run/docker.sock:ro" + + diff --git a/examples/docker-compose/odoo-and-db-ssl/traefik/certs/.gitignore b/examples/docker-compose/odoo-and-db-ssl/traefik/certs/.gitignore new file mode 100644 index 00000000..f2c4ee51 --- /dev/null +++ b/examples/docker-compose/odoo-and-db-ssl/traefik/certs/.gitignore @@ -0,0 +1 @@ +*.* diff --git a/examples/docker-compose/odoo-and-db-ssl/traefik/certs/README.md b/examples/docker-compose/odoo-and-db-ssl/traefik/certs/README.md new file mode 100644 index 00000000..eb160557 --- /dev/null +++ b/examples/docker-compose/odoo-and-db-ssl/traefik/certs/README.md @@ -0,0 +1,2 @@ +Place here certificates. +Name of certificate must be same as name of domain this sertificate is created for. diff --git a/examples/docker-compose/odoo-and-db-ssl/traefik/traefik-certs.yml b/examples/docker-compose/odoo-and-db-ssl/traefik/traefik-certs.yml new file mode 100644 index 00000000..2ec56ca0 --- /dev/null +++ b/examples/docker-compose/odoo-and-db-ssl/traefik/traefik-certs.yml @@ -0,0 +1,4 @@ +tls: + certificates: + - certFile: /certs/localhost.crt + keyFile: /certs/localhost.key From bbae1afac432bbbd578fc02f59859c842b82706e Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Fri, 15 Nov 2024 19:49:50 +0200 Subject: [PATCH 44/51] Update readme, added info about prebuilt docker images --- CHANGELOG.md | 1 + README.md | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98c9955b..f3c1f825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - New experimental command `odood deploy` that could be used to deploy production-ready Odoo instance. - Added experimental support for Odoo 18 - Added new command `odood repo fix-series` that allows to set series for all modules in repo to project's serie. +- Added automatic builds of docker images with pre-installed Odoo. ### Changed diff --git a/README.md b/README.md index 643cc341..59b5b8ac 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,14 @@ Following features currently implemented: - Odoo 17.0 (tested) - Odoo 18.0 (experimental) +## Prebuild docker-images with preinstalled Odoo and Odood + +You can use on of [prebuilt images](https://github.com/katyukha?tab=packages&repo_name=Odood) to run Odoo managed by Odood in containers: +- [Odoo 18](https://ghcr.io/katyukha/odood/odoo/18.0) +- [Odoo 17](https://ghcr.io/katyukha/odood/odoo/17.0) +- [Odoo 16](https://ghcr.io/katyukha/odood/odoo/16.0) +- [Odoo 15](https://ghcr.io/katyukha/odood/odoo/15.0) + ## Installation (as Debian Package) From b0807aedff3f1b0c59ee92e41ba98182635eff91 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 18 Nov 2024 23:14:14 +0200 Subject: [PATCH 45/51] Minor fix --- subpackages/lib/source/odood/lib/install/python.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subpackages/lib/source/odood/lib/install/python.d b/subpackages/lib/source/odood/lib/install/python.d index 0e1982e7..970532de 100644 --- a/subpackages/lib/source/odood/lib/install/python.d +++ b/subpackages/lib/source/odood/lib/install/python.d @@ -48,6 +48,8 @@ bool isSystemPythonSuitable(in Project project) { return (sys_py_ver >= Version(3, 7) && sys_py_ver < Version(3, 11)); if (project.odoo.serie <= OdooSerie(17)) return (sys_py_ver >= Version(3, 10) && sys_py_ver < Version(3, 12)); + if (project.odoo.serie <= OdooSerie(18)) + return (sys_py_ver >= Version(3, 10) && sys_py_ver < Version(3, 12)); /// Unknown odoo version return false; From 3fc591d7faa350df811dfb3e32381c7c5fab0850 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Tue, 10 Dec 2024 19:55:28 +0200 Subject: [PATCH 46/51] [ref] versioned: add ability to comapare version with string --- .../utils/source/odood/utils/versioned.d | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/subpackages/utils/source/odood/utils/versioned.d b/subpackages/utils/source/odood/utils/versioned.d index 53b4f57a..e02e1eeb 100644 --- a/subpackages/utils/source/odood/utils/versioned.d +++ b/subpackages/utils/source/odood/utils/versioned.d @@ -302,6 +302,12 @@ private enum VersionPart { return result; } + /// ditto + int opCmp(in string other) const { + return this.opCmp(Version(other)); + } + + /// Test version comparisons unittest { import unit_threaded.assertions; assert(Version("1.0.0-alpha") < Version("1.0.0-alpha.1")); @@ -317,6 +323,22 @@ private enum VersionPart { assert(Version("1.0.0-rc.2+build.5") != Version("1.0.0-rc.1+build.5")); } + /// Test comparisons with strings + unittest { + import unit_threaded.assertions; + assert(Version("1.0.0-alpha") < "1.0.0-alpha.1"); + assert(Version("1.0.0-alpha.1") < "1.0.0-alpha.beta"); + assert(Version("1.0.0-alpha.beta") < "1.0.0-beta"); + assert(Version("1.0.0-beta") < "1.0.0-beta.2"); + assert(Version("1.0.0-beta.2") < "1.0.0-beta.11"); + assert(Version("1.0.0-beta.11") < "1.0.0-rc.1"); + assert(Version("1.0.0-rc.1") < "1.0.0"); + assert(Version("1.0.0-rc.1") > "1.0.0-rc.1+build.5"); + assert(Version("1.0.0-rc.1+build.5") == "1.0.0-rc.1+build.5"); + assert(Version("1.0.0-rc.1+build.5") != "1.0.0-rc.1+build.6"); + assert(Version("1.0.0-rc.2+build.5") != "1.0.0-rc.1+build.5"); + } + bool opEquals(in Version other) const nothrow { return this.major == other.major && this.minor == other.minor && @@ -325,6 +347,12 @@ private enum VersionPart { this.build == other.build; } + /// ditto + bool opEquals(in string other) const { + return this.opEquals(Version(other)); + } + + /// Test equality checks unittest { import unit_threaded.assertions; Version("1.2.3").should == Version(1, 2, 3); @@ -333,4 +361,12 @@ private enum VersionPart { // TODO: more tests needed } + /// Test equality checks with strings + unittest { + import unit_threaded.assertions; + assert(Version("1.2.3") == "1.2.3"); + assert(Version("1.2") == "1.2"); + assert(Version("1.0.3") == "1.0.3"); + // TODO: more tests needed + } } From ae87508f4719748ecf8336849bdfc28468e242de Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Dec 2024 21:30:01 +0200 Subject: [PATCH 47/51] Bump python version to 3.10.16 for odoo 17 and 18 --- subpackages/lib/source/odood/lib/odoo/python.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subpackages/lib/source/odood/lib/odoo/python.d b/subpackages/lib/source/odood/lib/odoo/python.d index 54eef747..7acb2566 100644 --- a/subpackages/lib/source/odood/lib/odoo/python.d +++ b/subpackages/lib/source/odood/lib/odoo/python.d @@ -41,8 +41,8 @@ string suggestPythonVersion(in Project project) { if (project.odoo.serie == OdooSerie(16)) return "3.8.20"; if (project.odoo.serie == OdooSerie(17)) - return "3.10.15"; + return "3.10.16"; if (project.odoo.serie == OdooSerie(18)) - return "3.10.15"; + return "3.10.16"; return "3.8.20"; } From 56fdff36ce399d24e4d044ca698d0adf7b0160c3 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Dec 2024 21:52:10 +0200 Subject: [PATCH 48/51] [FIX] avoid installation of gevent 21.8.0, because its installation is buggy --- subpackages/lib/source/odood/lib/install/odoo.d | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/subpackages/lib/source/odood/lib/install/odoo.d b/subpackages/lib/source/odood/lib/install/odoo.d index 0d76ad20..d841758f 100644 --- a/subpackages/lib/source/odood/lib/install/odoo.d +++ b/subpackages/lib/source/odood/lib/install/odoo.d @@ -146,6 +146,17 @@ void installOdoo(in Project project) { "xlwt", ); } else { + // Patch requirements txt for Odoo 17 and 18 for python 3.10 + if (project.odoo.serie >= 16 && project.venv.py_version >= Version(3, 10) && project.venv.py_version < Version(3, 11)) { + info("Patching Odoo requirements.txt to avoid usage of gevent 21.8.0..."); + auto requirements_content = project.odoo.path.join("requirements.txt").readFileText() + .replaceAll( + regex(r"gevent==21\.8\.0", "g"), + "gevent==21.12.0"); + project.odoo.path.join("requirements.txt").writeFile(requirements_content); + warningf("requirements.txt:\n%s", project.odoo.path.join("requirements.txt").readFileText()); + } + info("Installing odoo dependencies (requirements.txt)"); project.venv.installPyRequirements( project.odoo.path.join("requirements.txt")); From dfdc69cf234638cb24d1d80ce24af0d2d8f509a4 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Dec 2024 22:25:48 +0200 Subject: [PATCH 49/51] Install wkhtmltopdf in docker image --- docker/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 2f7faebd..ffc7f3d2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,6 +10,7 @@ RUN apt-get update -qq && \ ca-certificates \ gnupg \ lsb-release \ + xfonts-75dpi xfonts-base libx11-6 libxcb1 libxext6 libxrender1 \ tzdata && \ locale-gen en_US.UTF-8 && \ locale-gen en_GB.UTF-8 && \ @@ -19,6 +20,9 @@ RUN apt-get update -qq && \ apt-key add - && \ apt-get update -qq && \ apt-get install -qqq -y --no-install-recommends --auto-remove $ODOOD_DEPENDENCIES && \ + wget --quiet -O /tmp/wkhtmltopdf.deb https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_$(dpkg --print-architecture).deb && \ + dpkg -i /tmp/wkhtmltopdf.deb && \ + rm -f /tmp/wkhtmltopdf.deb && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /root/.cache/pip/* From ff0ecad966003b7f18bca7acce484f06578af35e Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Dec 2024 22:31:13 +0200 Subject: [PATCH 50/51] [FIX] avoid using gevent 21.8.0 at all --- .../lib/source/odood/lib/install/odoo.d | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/subpackages/lib/source/odood/lib/install/odoo.d b/subpackages/lib/source/odood/lib/install/odoo.d index d841758f..f107b60c 100644 --- a/subpackages/lib/source/odood/lib/install/odoo.d +++ b/subpackages/lib/source/odood/lib/install/odoo.d @@ -146,16 +146,14 @@ void installOdoo(in Project project) { "xlwt", ); } else { - // Patch requirements txt for Odoo 17 and 18 for python 3.10 - if (project.odoo.serie >= 16 && project.venv.py_version >= Version(3, 10) && project.venv.py_version < Version(3, 11)) { - info("Patching Odoo requirements.txt to avoid usage of gevent 21.8.0..."); - auto requirements_content = project.odoo.path.join("requirements.txt").readFileText() - .replaceAll( - regex(r"gevent==21\.8\.0", "g"), - "gevent==21.12.0"); - project.odoo.path.join("requirements.txt").writeFile(requirements_content); - warningf("requirements.txt:\n%s", project.odoo.path.join("requirements.txt").readFileText()); - } + // Patch requirements txt to avoid using gevent 21.8.0 that requires build. + // See https://github.com/odoo/odoo/issues/187021 + info("Patching Odoo requirements.txt to avoid usage of gevent 21.8.0..."); + auto requirements_content = project.odoo.path.join("requirements.txt").readFileText() + .replaceAll( + regex(r"gevent==21\.8\.0", "g"), + "gevent==21.12.0"); + project.odoo.path.join("requirements.txt").writeFile(requirements_content); info("Installing odoo dependencies (requirements.txt)"); project.venv.installPyRequirements( From 5b9614fb31edafc053e671bcc87fe7fe83736174 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 12 Dec 2024 22:33:34 +0200 Subject: [PATCH 51/51] Do not test on ubuntu 23.04 (end of life) dd deployment tests for ubuntu 20.04 and 22.04 --- .github/workflows/test-deployments.yml | 5 ++--- .github/workflows/test-os-integrations.yml | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-deployments.yml b/.github/workflows/test-deployments.yml index 42e267e9..2d0e4f08 100644 --- a/.github/workflows/test-deployments.yml +++ b/.github/workflows/test-deployments.yml @@ -47,9 +47,8 @@ jobs: matrix: image: - "debian:bullseye" - #- "ubuntu:20.04" - #- "ubuntu:22.04" - - "ubuntu:23.04" + - "ubuntu:20.04" + - "ubuntu:22.04" - "ubuntu:24.04" odoo_version: - "18.0" diff --git a/.github/workflows/test-os-integrations.yml b/.github/workflows/test-os-integrations.yml index 6d826621..f35a5782 100644 --- a/.github/workflows/test-os-integrations.yml +++ b/.github/workflows/test-os-integrations.yml @@ -48,7 +48,6 @@ jobs: - "debian:bullseye" - "ubuntu:20.04" - "ubuntu:22.04" - - "ubuntu:23.04" - "ubuntu:24.04" runs-on: ubuntu-22.04 needs: