diff --git a/copier.yml b/copier.yml index cffdfe5..65b7ace 100644 --- a/copier.yml +++ b/copier.yml @@ -31,6 +31,13 @@ branch_name: default: "18.0" help: Odoo version +# TODO change the place of this option before merging +# I just put here to avoid conflict +# it should be moved after org_name +use_manual_bump: + type: bool + help: Bump your image manually instead of using UI, this allow to use migrate script + odoo_version: # odoo_version is more readable # branch_name is required by huddle, more generic diff --git a/src/.gitlab-ci.yml.jinja b/src/.gitlab-ci.yml.jinja index b6bea26..687f6b1 100644 --- a/src/.gitlab-ci.yml.jinja +++ b/src/.gitlab-ci.yml.jinja @@ -52,6 +52,7 @@ stages: # because usually it's only # needed before the merge - test +{% if use_manual_bump %} - docker_push{% endif %} before_script: # TODO: manage mulitple preprod ? @@ -421,6 +422,26 @@ review_preprod: - job: "build" optional: true +{# # TODO we should merge this two solution +# But as it need time and test get the two solution for now +# so we can use the same template, update project and then merge it #} +{% if use_manual_bump %} +# Send the docker image to the registry in order to be downloaded in prod +docker_push: + stage: docker_push + script: + - export TAG="${CI_COMMIT_MESSAGE//Bump version /}" + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker tag $BUILD_NAME $CI_REGISTRY_IMAGE:latest + - docker push $CI_REGISTRY_IMAGE:latest + - docker tag $BUILD_NAME $CI_REGISTRY_IMAGE:$TAG + - docker push $CI_REGISTRY_IMAGE:$TAG + rules: + - if: $CI_COMMIT_TITLE =~ /^Bump version/ && $AK_IS_MR == null + needs: + - update_db + - test +{% else %} prepare_release: stage: deploy script: @@ -450,6 +471,7 @@ prepare_release: needs: - build + publish: # creates a gitlab release stage: deploy @@ -519,7 +541,7 @@ publish: when: never - if: $AK_IS_MAJOR_BRANCH == "true" # run on protected branches only - +{% endif %} init_source_cache: stage: maintenance diff --git a/src/odoo/bin/migrate b/src/odoo/bin/migrate new file mode 100755 index 0000000..bff376d --- /dev/null +++ b/src/odoo/bin/migrate @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# pylint: disable=print-used + +import logging +import os + +from click_odoo_contrib.update import main + +from odoo import release, sql_db +from odoo.modules import module +from odoo.modules.registry import Registry + +_logger = logging.getLogger(__name__) + +TOP_MODULE_PATH = "/odoo/local-src/custom_all" + +FAKE_VERSION = f"{release.major_version}.9999.9.9" + +ori_load_information_from_description_file = ( + module.load_information_from_description_file +) + + +# As odoo only run migration script when the version change +# We patch odoo when loading the manifest to increment virtually the version when +# a "pending" migration script exist +# The version is always set to the number X.X.9999.9.9 +# Note: odoo natively support to process the migration in the directory 0.0.0 +# so we do not need to hack this part +def load_information_from_description_file(module_name, mod_path=None): + info = ori_load_information_from_description_file(module_name, mod_path=mod_path) + if not mod_path: + mod_path = module.get_module_path(module_name, downloaded=True) + if "local-src" in mod_path: + if os.path.exists(f"{mod_path}/migrations/0.0.0"): + files = os.listdir(f"{mod_path}/migrations/0.0.0") + if files != [".keep"]: + # If we have real file in 0.0.0 + info["version"] = FAKE_VERSION + return info + + +module.load_information_from_description_file = load_information_from_description_file + + +# Process before-XXX.sql script in custom_all/migrations/{version}/ + + +def add_sql_migration(todo, version): + path = f"{TOP_MODULE_PATH}/migrations/{version}" + for filename in os.listdir(path): + if filename.startswith("before") and filename[-4:] == ".sql": + file_path = f"{path}/{filename}" + todo.append((file_path, open(file_path).read())) + + +def get_before_request(cr): + cr.execute("SELECT latest_version FROM ir_module_module WHERE name='custom_all'") + todo = [] + db_version = cr.fetchone() + if not db_version: + _logger.error("No version found for custom_all, skip begin script") + db_version = db_version[0] + migr_path = f"{TOP_MODULE_PATH}/migrations" + if os.path.exists(migr_path): + versions = os.listdir(migr_path) + versions.sort() + if versions and versions[0] == "0.0.0": + # always run pending version add the end + versions.append(versions.pop(0)) + # Run all version that are superior to the db version + # And run version of 0.0.0 if FAKE_VERSION is not applied + for version in versions: + if version > db_version or version == "0.0.0" and FAKE_VERSION > db_version: + add_sql_migration(todo, version) + return todo + + +ori_new = Registry.new + + +@classmethod +def new(cls, db_name, force_demo=False, status=None, update_module=False): + conn = sql_db.db_connect(db_name) + with conn.cursor() as cr: + for file_path, requests in get_before_request(cr): + _logger.info( + "Execute before sql request \n=== %s \n%s===\n", file_path, requests + ) + cr.execute(requests) + return ori_new( + db_name, force_demo=force_demo, status=status, update_module=update_module + ) + + +Registry.new = new + + +# Call native click-odoo-update + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/src/odoo/start-entrypoint.d/010_click_odoo_update b/src/odoo/start-entrypoint.d/010_click_odoo_update.jinja similarity index 90% rename from src/odoo/start-entrypoint.d/010_click_odoo_update rename to src/odoo/start-entrypoint.d/010_click_odoo_update.jinja index 66c3331..cc24519 100755 --- a/src/odoo/start-entrypoint.d/010_click_odoo_update +++ b/src/odoo/start-entrypoint.d/010_click_odoo_update.jinja @@ -20,4 +20,9 @@ then exit 0 fi echo "START UPDATING USING CLICK ODOO" + +{% if use_manual_bump %} +migrate --i18n-overwrite +{% else %} click-odoo-update --i18n-overwrite +{% endif %} diff --git a/src/{% if use_manual_bump %}bump{% endif %} b/src/{% if use_manual_bump %}bump{% endif %} new file mode 100755 index 0000000..c3ecd44 --- /dev/null +++ b/src/{% if use_manual_bump %}bump{% endif %} @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# pylint: disable=print-used + +import ast +import os +import subprocess +from datetime import datetime + +import click + +ODOO_VERSION = "14.0" + + +@click.command() +def main(): + subprocess.run("git pull", shell=True, check=True) + version = datetime.now().strftime(f"{ODOO_VERSION}.%y%m.%d.0") + with open("odoo/local-src/custom_all/__manifest__.py") as f: + data = ast.literal_eval(f.read()) + last_version = data["version"] + + # increment last digit if needed + if last_version >= version: + odoo_version, zero, year_month, day, inc = last_version.split(".") + inc = str(int(inc) + 1) + version = ".".join([odoo_version, zero, year_month, day, inc]) + + # increment modules versions + for module_name in os.listdir("odoo/local-src"): + module_path = f"odoo/local-src/{module_name}" + manifest_path = f"{module_path}/__manifest__.py" + # Check if it's an odoo module + if os.path.exists(manifest_path): + update_version = False + # in case of pending migration script increment it + if os.path.exists(f"{module_path}/migrations/0.0.0"): + files = os.listdir(f"{module_path}/migrations/0.0.0") + if files != [".keep"]: + subprocess.run( + f"mkdir {module_path}/migrations/{version}", + shell=True, + check=True, + ) + subprocess.run( + ( + f"git mv {module_path}/migrations/0.0.0/* " + f"{module_path}/migrations/{version}" + ), + shell=True, + check=True, + ) + update_version = True + if update_version or module_name == "custom_all": + print(f"Update version of {module_name} to {version}") + with open(manifest_path) as f: + raw_data = f.read() + data = ast.literal_eval(raw_data) + with open(manifest_path, "w") as f: + raw_data = raw_data.replace(data["version"], version) + f.write(raw_data) + subprocess.run(f"git add {manifest_path}", shell=True, check=True) + + subprocess.run(f"git commit -m'Bump version {version}'", shell=True, check=True) + subprocess.run(f"git tag {version}", shell=True, check=True) + subprocess.run("git push origin --tag", shell=True, check=True) + subprocess.run(f"git push origin {ODOO_VERSION}", shell=True, check=True) + + +if __name__ == "__main__": + main()