merge 1.3.1
This commit is contained in:
parent
bf07bc1865
commit
a5f7f2e88c
37
CHANGES.rst
37
CHANGES.rst
|
|
@ -6,6 +6,43 @@ This file compiles releases and changes made in
|
|||
|
||||
.. towncrier release notes start
|
||||
|
||||
odoo-openupgrade-wizard 1.3.1 (2025-09-18)
|
||||
==========================================
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Fix BSD mkdir incompatibility on macOS by using single-character
|
||||
flags for 'mode' and 'parents' for cross-platform folder creation (#39)
|
||||
- Fix debian buster Dockerfile. It uses the old https://deb.debian.org
|
||||
instead of https://archive.debian.org.
|
||||
- Improve error handling for missing config file outside initialized
|
||||
environment.
|
||||
- Prevent creating a log file outside of an initialized directory.
|
||||
- Set 'rm=True' when building Docker images, ensuring intermediate (i.e.
|
||||
orphaned) containers are automatically removed after builds and keeping
|
||||
local Docker environments clean.
|
||||
|
||||
By default, the docker build CLI now sets --rm=true, but the SDK has
|
||||
kept the old default of False to preserve backward compatibility.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
- Many improvements/additions to README.md and help string, including missing
|
||||
Command help, additional examples, a Quick Start Guide, standard technical
|
||||
writing changes, etc.
|
||||
- Remove obsolete ROADMAP file. Team now uses issues on gitlab.
|
||||
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
- Do not set False to an argument that is hint typed as string. Using None
|
||||
instead.
|
||||
|
||||
|
||||
odoo-openupgrade-wizard 1.3.0 (2025-05-04)
|
||||
==========================================
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
* Boris GALLET, since September 2024
|
||||
* Ahmet YIĞIT BUDAK, from [Altinkaya](https://www.altinkaya.com/fr), since October 2024
|
||||
* Alexandre AUBIN, from [Coopaname](https://www.coopaname.coop/), since October 2024
|
||||
* Sergio Zanchetta, from [PNLug](https://www.pnlug.it/), since January 2025
|
||||
* Ken WOYCHESKO, since May 2025
|
||||
|
||||
# Reviewers
|
||||
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
|||
writable=True,
|
||||
resolve_path=True,
|
||||
),
|
||||
help="Folder that will contains all the configuration of the wizard"
|
||||
" and all the Odoo code required to make the migrations. Let empty to"
|
||||
" use current folder (./).",
|
||||
help="Directory that will contain all the configuration of the wizard "
|
||||
"and all the Odoo code required to perform the migrations. Leave "
|
||||
"empty to use current directory (./).",
|
||||
)
|
||||
@click.option(
|
||||
"-c",
|
||||
|
|
@ -69,7 +69,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
|||
),
|
||||
help=(
|
||||
f"Configuration file to use. By default, a file named "
|
||||
f'"{DEFAULT_CONFIG_FILE}" in the environment folder will be used.'
|
||||
f'"{DEFAULT_CONFIG_FILE}" in the environment directory will be used.'
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
|
|
@ -80,7 +80,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
|||
),
|
||||
help=(
|
||||
f"Modules file to use. By default, a file named "
|
||||
f'"{DEFAULT_MODULES_FILE}" in the environment folder will be used.'
|
||||
f'"{DEFAULT_MODULES_FILE}" in the environment directory will be used.'
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
|
|
@ -88,17 +88,23 @@ DEFAULT_MODULES_FILE = "modules.csv"
|
|||
type=click.Path(
|
||||
exists=True, file_okay=False, writable=True, resolve_path=True
|
||||
),
|
||||
help="Folder that contains the Odoo filestore of the database(s)"
|
||||
" to migrate. Let empty to use the subfolder 'filestore' of the"
|
||||
" environment folder.",
|
||||
help="Directory that contains the Odoo filestore of the database(s) to "
|
||||
"migrate. Leave empty to use the subdirectory 'filestore' of the "
|
||||
"environment directory.",
|
||||
)
|
||||
@click.option("-l", "--log-level", type=LogLevel(), default=logging.INFO)
|
||||
@click.pass_context
|
||||
def main(
|
||||
ctx, env_folder, config_file, modules_file, filestore_folder, log_level
|
||||
):
|
||||
"""
|
||||
Provides a command set to perform odoo Community Edition migrations.
|
||||
"""Provides a command set to perform Odoo Community Edition migrations.
|
||||
|
||||
Instructions are provided in the README.md file, or see the
|
||||
help provided for each 'Command' listed below. For
|
||||
example, to learn more about the `init` command,
|
||||
run:
|
||||
|
||||
`oow init --help`
|
||||
"""
|
||||
date_begin = datetime.datetime.now()
|
||||
logger.remove()
|
||||
|
|
@ -118,16 +124,6 @@ def main(
|
|||
script_folder_path = env_folder_path / Path("./scripts/")
|
||||
log_folder_path = env_folder_path / Path("./log/")
|
||||
|
||||
# ensure log folder exists
|
||||
ensure_folder_exists(log_folder_path, git_ignore_content=True)
|
||||
|
||||
# Create log file
|
||||
log_prefix = "{}__{}".format(
|
||||
date_begin.strftime("%Y_%m_%d__%H_%M_%S"), ctx.invoked_subcommand
|
||||
)
|
||||
log_file_path = log_folder_path / Path(log_prefix + ".log")
|
||||
logger.add(log_file_path)
|
||||
|
||||
if config_file:
|
||||
config_file_path = Path(config_file)
|
||||
else:
|
||||
|
|
@ -138,24 +134,38 @@ def main(
|
|||
else:
|
||||
module_file_path = env_folder_path / Path(DEFAULT_MODULES_FILE)
|
||||
|
||||
if config_file_path.exists():
|
||||
# Load the main configuration file
|
||||
with open(config_file_path) as file:
|
||||
config = yaml.safe_load(file)
|
||||
ctx.obj["config"] = config
|
||||
|
||||
# ensure log folder exists
|
||||
ensure_folder_exists(log_folder_path, git_ignore_content=True)
|
||||
|
||||
# Create log file
|
||||
log_prefix = "{}__{}".format(
|
||||
date_begin.strftime("%Y_%m_%d__%H_%M_%S"), ctx.invoked_subcommand
|
||||
)
|
||||
log_file_path = log_folder_path / Path(log_prefix + ".log")
|
||||
logger.add(log_file_path)
|
||||
|
||||
ctx.obj["log_prefix"] = log_prefix
|
||||
elif ctx.invoked_subcommand not in ("init", None):
|
||||
ctx.fail(
|
||||
f"Environment not initialized. "
|
||||
f"Expected config file at: {config_file_path}",
|
||||
)
|
||||
|
||||
# Add all global values in the context
|
||||
ctx.obj["env_folder_path"] = env_folder_path
|
||||
ctx.obj["src_folder_path"] = src_folder_path
|
||||
ctx.obj["filestore_folder_path"] = filestore_folder_path
|
||||
ctx.obj["script_folder_path"] = script_folder_path
|
||||
ctx.obj["log_folder_path"] = log_folder_path
|
||||
ctx.obj["log_prefix"] = log_prefix
|
||||
ctx.obj["config_file_path"] = config_file_path
|
||||
ctx.obj["module_file_path"] = module_file_path
|
||||
|
||||
# Load the main configuration file
|
||||
if config_file_path.exists():
|
||||
with open(config_file_path) as file:
|
||||
config = yaml.safe_load(file)
|
||||
ctx.obj["config"] = config
|
||||
elif ctx.invoked_subcommand != "init":
|
||||
raise
|
||||
|
||||
|
||||
main.add_command(copydb)
|
||||
main.add_command(restoredb)
|
||||
|
|
|
|||
|
|
@ -10,17 +10,20 @@ from odoo_openupgrade_wizard.tools import (
|
|||
"-s",
|
||||
"--source",
|
||||
type=str,
|
||||
help="Name of the database to copy",
|
||||
help="Name of the source database to copy.",
|
||||
)
|
||||
@click.option(
|
||||
"-d",
|
||||
"--dest",
|
||||
type=str,
|
||||
help="Name of the new database",
|
||||
help="Name of the destination database to create.",
|
||||
)
|
||||
@click.pass_context
|
||||
def copydb(ctx, source, dest):
|
||||
"""Create an Odoo database by copying an existing one.
|
||||
it will copy the postgres database and the filestore.
|
||||
"""Create a new Odoo database by copying another.
|
||||
|
||||
This command duplicates both the PostgreSQL database and its associated
|
||||
filestore.
|
||||
|
||||
"""
|
||||
click_odoo_contrib.copydb(ctx, source, dest)
|
||||
|
|
|
|||
|
|
@ -17,11 +17,16 @@ from odoo_openupgrade_wizard.tools.tools_system import get_local_user_id
|
|||
@versions_options
|
||||
@click.pass_context
|
||||
def docker_build(ctx, versions):
|
||||
"""Build Odoo Docker Images and pull Postgres image"""
|
||||
"""Build Docker images and pull PostgreSQL image.
|
||||
|
||||
This command prepares the Docker environment needed for running migration
|
||||
steps. Make sure to run `oow get-code` first to ensure all required code
|
||||
and requirements files are available for each version.
|
||||
"""
|
||||
|
||||
# Pull DB image
|
||||
logger.info(
|
||||
"Pulling the postgresql docker image. This can take a while..."
|
||||
"Pulling the PostgreSQL Docker image. This can take a while..."
|
||||
)
|
||||
pull_image(ctx.obj["config"]["postgres_image_name"])
|
||||
|
||||
|
|
@ -32,16 +37,16 @@ def docker_build(ctx, versions):
|
|||
)
|
||||
if not odoo_requirement_file_path.exists():
|
||||
logger.error(
|
||||
"Building Odoo docker image for version {odoo_version}, "
|
||||
"Cannot build Odoo Docker image for version {odoo_version}, "
|
||||
"because file {odoo_requirement_file_path} cannot be found. "
|
||||
"Have your run the get-code command ?",
|
||||
"Have you run the get-code command?",
|
||||
odoo_version=odoo_version,
|
||||
odoo_requirement_file_path=odoo_requirement_file_path,
|
||||
)
|
||||
continue
|
||||
|
||||
logger.info(
|
||||
f"Building Odoo docker image for version '{odoo_version}'."
|
||||
f"Building Odoo Docker image for version '{odoo_version}'."
|
||||
" This can take a while..."
|
||||
)
|
||||
image = build_image(
|
||||
|
|
|
|||
|
|
@ -17,33 +17,34 @@ from odoo_openupgrade_wizard.tools.tools_system import dump_filestore
|
|||
"--database-path",
|
||||
type=click.Path(writable=True, resolve_path=True),
|
||||
required=True,
|
||||
help="Path to the database dump relative project folder.",
|
||||
help="Destination path for the database dump relative to the project "
|
||||
"directory.",
|
||||
)
|
||||
@click.option(
|
||||
"--database-format",
|
||||
type=click.Choice(("p", "c", "d", "t")),
|
||||
default="c",
|
||||
help="Database format (see pg_dump options): plain sql text (p), "
|
||||
"custom format compressed (c), directory (d), tar file (t).",
|
||||
help="Database format (see pg_dump options): plain SQL (p), "
|
||||
"custom format compressed (c), directory (d), or tar file (t).",
|
||||
)
|
||||
@click.option(
|
||||
"--filestore-path",
|
||||
type=click.Path(writable=True, resolve_path=True),
|
||||
required=True,
|
||||
help="Path to the filestore backup.",
|
||||
help="Destination path for the filestore backup.",
|
||||
)
|
||||
@click.option(
|
||||
"--filestore-format",
|
||||
type=click.Choice(("d", "t", "tgz")),
|
||||
default="tgz",
|
||||
help="Filestore format: directory (d), tar file (t), "
|
||||
"tar file compressed with gzip (tgz)",
|
||||
"or tar file compressed with gzip (tgz)",
|
||||
)
|
||||
@click.option(
|
||||
"--force",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Overwrite file if they already exists.",
|
||||
help="Overwrite files if they already exist.",
|
||||
)
|
||||
@click.pass_context
|
||||
def dumpdb(
|
||||
|
|
@ -55,7 +56,14 @@ def dumpdb(
|
|||
filestore_format,
|
||||
force,
|
||||
):
|
||||
"""Create an dump of an Odoo database and its filestore."""
|
||||
"""Create a dump of an Odoo database and filestore.
|
||||
|
||||
Creates a backup of the selected Odoo database and
|
||||
its associated filestore. Both output locations must
|
||||
reside inside the project directory. Existing files
|
||||
will be overwritten if --force is specified.
|
||||
"""
|
||||
|
||||
database_path = pathlib.Path(database_path)
|
||||
filestore_path = pathlib.Path(filestore_path)
|
||||
|
||||
|
|
@ -67,7 +75,7 @@ def dumpdb(
|
|||
):
|
||||
ctx.fail(
|
||||
"database-path should be inside the project path to allow "
|
||||
"postgresql to write to it."
|
||||
"PostgreSQL to write to it."
|
||||
)
|
||||
|
||||
# Fail if dumps already exists and force argument not given
|
||||
|
|
|
|||
|
|
@ -17,35 +17,43 @@ from odoo_openupgrade_wizard.tools.tools_system import (
|
|||
dir_okay=False,
|
||||
),
|
||||
default="./analysis.html",
|
||||
help="Path where the HTML analysis report will be saved. "
|
||||
"Default is './analysis.html'",
|
||||
)
|
||||
@click.option(
|
||||
"--extra-modules",
|
||||
"extra_modules_list",
|
||||
# TODO, add a callback to check the quality of the argument
|
||||
help="Coma separated modules to analyse. If not set, the modules.csv"
|
||||
" file will be used to define the list of module to analyse."
|
||||
"Ex: 'account,product,base'",
|
||||
help="Comma-separated list of modules to analyze. If not set, "
|
||||
"modules.csv will be used. Example: 'account,product,base'.",
|
||||
)
|
||||
@click.option(
|
||||
"--time-unit",
|
||||
type=click.Choice(["hour", "minute", "separator"]),
|
||||
default="separator",
|
||||
show_default=True,
|
||||
help="Select unit to display time in the report. "
|
||||
help="Format to use for displaying time in the report. "
|
||||
"*separator* display time as `HHH<sep>MM`, "
|
||||
"*hour* display time as decimal hour, "
|
||||
"*min* display time as minute (rounded).",
|
||||
"*min* display time as minutes (rounded).",
|
||||
)
|
||||
@click.option(
|
||||
"--time-separator",
|
||||
default=":",
|
||||
help="Specify time separator, if time-unit is separator. "
|
||||
"Default to `:` (it will produce time like this HHH:MM).",
|
||||
help="Character to use as a separator in time output. "
|
||||
"Used only if --time-unit=separator. Default is ':' (e.g. HHH:MM).",
|
||||
)
|
||||
@click.pass_context
|
||||
def estimate_workload(
|
||||
ctx, analysis_file_path, extra_modules_list, time_unit, time_separator
|
||||
):
|
||||
"""Estimate workload and create an analysis report.
|
||||
|
||||
This command estimates the workload required for an Odoo
|
||||
migration based on the module set provided. The output is
|
||||
an HTML report showing time estimations for each module.
|
||||
"""
|
||||
|
||||
# Analyse
|
||||
analysis = Analysis(ctx)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,29 @@ from odoo_openupgrade_wizard.tools.tools_odoo import (
|
|||
exists=True,
|
||||
dir_okay=False,
|
||||
),
|
||||
help="List of python files that will be executed, replacing the default"
|
||||
" scripts placed in the migration step folder.",
|
||||
help="""List of Python files to execute, with either an absolute path
|
||||
or path relative to the project directory. With either method, the
|
||||
path must be located inside the project directory so that the
|
||||
Docker container can access it.
|
||||
|
||||
Files will be executed in
|
||||
the order listed. If no files are specified, all Python (.py) files
|
||||
in the `step` directory will be sorted alphabetically and then
|
||||
executed in order.
|
||||
|
||||
See README.md for more information and examples.""",
|
||||
)
|
||||
@click.pass_context
|
||||
def execute_script_python(ctx, step, database, script_file_path):
|
||||
"""Execute Python scripts for a migration step.
|
||||
|
||||
Executes one or more custom Python scripts in the context of a specific
|
||||
migration step, using the Odoo shell (with full ORM access). This command
|
||||
allows you to manually run Python logic outside of the default
|
||||
post-migration.py file for a given step. It allows fine-tuning
|
||||
of migration behavior by manually specifying logic.
|
||||
"""
|
||||
|
||||
migration_step = get_migration_step_from_options(ctx, step)
|
||||
|
||||
execute_click_odoo_python_files(
|
||||
|
|
|
|||
|
|
@ -22,11 +22,21 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
|
|||
exists=True,
|
||||
dir_okay=False,
|
||||
),
|
||||
help="List of SQL files that will be executed, replacing the default"
|
||||
" scripts placed in the migration step folder.",
|
||||
help="List of SQL files to execute. Files will be executed in the order "
|
||||
"listed. If no files are specified, all SQL files (.sql) in the "
|
||||
"step's directory will be sorted alphabetically and then executed "
|
||||
"in order.",
|
||||
)
|
||||
@click.pass_context
|
||||
def execute_script_sql(ctx, step, database, script_file_path):
|
||||
"""Execute SQL scripts for a migration step.
|
||||
|
||||
Executes one or more custom SQL scripts against the specified database,
|
||||
using the PostgreSQL Docker container. This command allows you to manually
|
||||
run SQL logic, allowing you to test or apply SQL changes in the context
|
||||
of a specific migration step — outside the automatic oow upgrade process.
|
||||
"""
|
||||
|
||||
migration_step = get_migration_step_from_options(ctx, step)
|
||||
|
||||
execute_sql_files_pre_migration(
|
||||
|
|
|
|||
|
|
@ -28,11 +28,24 @@ from odoo_openupgrade_wizard.tools.tools_system import ensure_folder_writable
|
|||
"-m",
|
||||
"--modules",
|
||||
type=str,
|
||||
help="Coma-separated list of modules to analysis."
|
||||
" Let empty to analyse all the Odoo modules.",
|
||||
help="Comma-separated list of modules to analyse."
|
||||
" Leave empty to analyse all the Odoo modules.",
|
||||
)
|
||||
@click.pass_context
|
||||
def generate_module_analysis(ctx, step, database, modules):
|
||||
"""Analyzes changes in data model & module data.
|
||||
|
||||
Performs an analysis between the target version (represented by the step
|
||||
parameter) and the previous version to indicate how the data model and
|
||||
module data have changed between the two versions (uses the
|
||||
OCA/server-tools `upgrade_analysis` tool internally).
|
||||
|
||||
You can also use this function to analyze differences for custom & OCA
|
||||
modules between several versions (e.g. in case of refactoring).
|
||||
|
||||
See the README.md for more information, including the location of the
|
||||
resultant analysis files.
|
||||
"""
|
||||
migration_steps = get_migration_steps_from_options(ctx, step - 1, step)
|
||||
|
||||
initial_step = migration_steps[0].copy()
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ from odoo_openupgrade_wizard.tools.tools_system import git_aggregate
|
|||
type=int,
|
||||
default=10,
|
||||
help="Jobs used to call the git-aggregate command."
|
||||
" reasonably set to 10 by default.",
|
||||
" Reasonably set to 10 by default.",
|
||||
)
|
||||
@click.pass_context
|
||||
def get_code(ctx, versions, jobs):
|
||||
"""Get code by running gitaggregate command for each version"""
|
||||
"""Get all required source code for each version.
|
||||
|
||||
Downloads all required Odoo source code and dependencies for each version
|
||||
defined in your migration (uses the `gitaggregate` tools internally).
|
||||
"""
|
||||
|
||||
for odoo_version in get_odoo_versions_from_options(ctx, versions):
|
||||
folder_path = get_odoo_env_path(ctx, odoo_version)
|
||||
|
|
|
|||
|
|
@ -17,12 +17,23 @@ from odoo_openupgrade_wizard.tools.tools_system import (
|
|||
"--extra-modules",
|
||||
"extra_modules_list",
|
||||
# TODO, add a callback to check the quality of the argument
|
||||
help="Coma separated modules to analyse. If not set, the modules.csv"
|
||||
" file will be used to define the list of module to analyse."
|
||||
"Ex: 'account,product,base'",
|
||||
help="Comma-separated list of modules to analyze. If not set, "
|
||||
"modules.csv will be used. Example: 'account,product,base'.",
|
||||
)
|
||||
@click.pass_context
|
||||
def guess_requirement(ctx, extra_modules_list):
|
||||
"""Guess system & Python requirements for modules.
|
||||
|
||||
Analyzes the list of modules defined in your modules.csv file
|
||||
to generate the required Python and Debian package dependencies per
|
||||
environment.
|
||||
|
||||
For each module and each version, this command tries to parse the
|
||||
corresponding __manifest__.py file (and, if present, the setup.py
|
||||
file). It then appends any discovered requirements to the appropriate
|
||||
addons_debian_requirements.txt and addons_python_requirements.txt files
|
||||
present in each env directory.
|
||||
"""
|
||||
# Analyse
|
||||
analysis = Analysis(ctx)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,42 +19,44 @@ from odoo_openupgrade_wizard.tools.tools_system import (
|
|||
required=True,
|
||||
prompt=True,
|
||||
type=str,
|
||||
help="Name of your project without spaces neither special"
|
||||
" chars or uppercases. exemple 'my-customer-9-12'."
|
||||
" This will be used to tag with a friendly"
|
||||
" name the odoo docker images.",
|
||||
help="Name of your project without spaces, special"
|
||||
" characters, or uppercases. Example: 'my-customer-9-12'."
|
||||
" This will be used to tag the Odoo Docker images "
|
||||
" with a friendly name.",
|
||||
)
|
||||
@click.option(
|
||||
"--initial-version",
|
||||
required=True,
|
||||
prompt=True,
|
||||
type=click.Choice(get_version_options("initial")),
|
||||
help="Initial Odoo version to migrate from.",
|
||||
)
|
||||
@click.option(
|
||||
"--final-version",
|
||||
required=True,
|
||||
prompt=True,
|
||||
type=click.Choice(get_version_options("final")),
|
||||
help="Target Odoo version to migrate to.",
|
||||
)
|
||||
@click.option(
|
||||
"--postgresql-version",
|
||||
required=True,
|
||||
prompt=True,
|
||||
help="The version of postgresql that will be used"
|
||||
" to create the postgresql container.Ex : '9.1', '16', ..."
|
||||
" The version should be available in docker hub."
|
||||
" (https://hub.docker.com/_/postgres)"
|
||||
" avoid the 'latest' version if you want a deterministic installation."
|
||||
" Key Point: If your current production server uses Postgresql version A"
|
||||
" and if your future production server usees Postgresql version B,"
|
||||
" you should select here a version X, with A <= X <= B.",
|
||||
help="""The version of PostgreSQL that will be used
|
||||
to create the PostgreSQL container. Example: '9.1', '16', etc.
|
||||
The version should be available in Docker hub.
|
||||
(https://hub.docker.com/_/postgres)
|
||||
Avoid the 'latest' version if you want a deterministic installation.
|
||||
Key Point: If your current production server uses PostgreSQL version A
|
||||
and your future production server will use PostgreSQL version B,
|
||||
you should select here a version X, with A <= X <= B.""",
|
||||
)
|
||||
@click.option(
|
||||
"--extra-repository",
|
||||
"extra_repository_list",
|
||||
# TODO, add a callback to check the quality of the argument
|
||||
help="Coma separated extra repositories to use in the odoo environment."
|
||||
"Ex: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
|
||||
help="Comma-separated extra repositories to use in the Odoo environment."
|
||||
"Example: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
|
||||
)
|
||||
@click.pass_context
|
||||
def init(
|
||||
|
|
@ -65,8 +67,10 @@ def init(
|
|||
postgresql_version,
|
||||
extra_repository_list,
|
||||
):
|
||||
"""Initialize OOW Environment based on the initial and
|
||||
the final version of Odoo you want to migrate.
|
||||
"""Initialize the OOW project environment.
|
||||
|
||||
This command sets up the project folder structure, configuration
|
||||
files, and default templates needed to begin an Odoo migration.
|
||||
"""
|
||||
|
||||
# Handle arguments
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
|
|||
@demo_option
|
||||
@click.pass_context
|
||||
def install_from_csv(ctx, database, with_demo):
|
||||
"""Install modules from a CSV file.
|
||||
|
||||
This command reads the modules.csv file and installs the
|
||||
modules listed for a specific Odoo version. The database will be
|
||||
created if it doesn't exist.
|
||||
"""
|
||||
migration_step = get_migration_step_from_options(ctx, 1)
|
||||
ensure_database(ctx, database, state="present")
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@ def versions_options(function):
|
|||
"-v",
|
||||
"--versions",
|
||||
type=str,
|
||||
help="Coma-separated values of odoo versions for which"
|
||||
" you want to perform the operation."
|
||||
" Let empty to perform the operation on all the versions"
|
||||
" of the project",
|
||||
help="Comma-separated Odoo versions to target. Leave empty to "
|
||||
"perform the operation on all versions in the project",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
|
@ -30,7 +28,7 @@ def first_step_option(function):
|
|||
function = click.option(
|
||||
"--first-step",
|
||||
type=int,
|
||||
help="First step for which to perform the operation",
|
||||
help="First step to include in the operation.",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
|
@ -39,7 +37,7 @@ def last_step_option(function):
|
|||
function = click.option(
|
||||
"--last-step",
|
||||
type=int,
|
||||
help="Last step for which to perform the operation",
|
||||
help="Last step to include in the operation.",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
|
@ -48,7 +46,7 @@ def demo_option(function):
|
|||
function = click.option(
|
||||
"--with-demo/--without-demo",
|
||||
default=False,
|
||||
help="Create database with or without demo data.",
|
||||
help="Whether to include demo data when creating the database.",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
|
@ -61,7 +59,7 @@ def database_option_required(function):
|
|||
prompt=True,
|
||||
default="postgres",
|
||||
type=str,
|
||||
help="Odoo Database for which you want to perform the operation.",
|
||||
help="Name of the Odoo database to operate on. Default is 'postgres'.",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,29 @@ from odoo_openupgrade_wizard.tools.tools_postgres import execute_psql_command
|
|||
|
||||
@click.command(context_settings={"ignore_unknown_options": True})
|
||||
@database_option_required
|
||||
@click.option("-c", "--command", "request")
|
||||
@click.option("--pager/--no-pager", default=True)
|
||||
@click.option(
|
||||
"-c",
|
||||
"--command",
|
||||
"request",
|
||||
help="SQL command to execute inside the container.",
|
||||
)
|
||||
@click.option(
|
||||
"--pager/--no-pager",
|
||||
default=True,
|
||||
help="Enable or disable pager when displaying output.",
|
||||
)
|
||||
@click.argument("psql_args", nargs=-1, type=click.UNPROCESSED)
|
||||
@click.pass_context
|
||||
def psql(ctx, request, database, pager, psql_args):
|
||||
"""Run psql in the postgres container. Fill any parameters of psql
|
||||
as PSQLARGS.
|
||||
"""Run a SQL command in the PostgreSQL container.
|
||||
|
||||
This command executes the provided SQL command using `psql`
|
||||
within the database container. Use --command for inline SQL
|
||||
or pass additional arguments directly to psql via PSQLARGS.
|
||||
|
||||
See the README.md for more information.
|
||||
"""
|
||||
|
||||
result = execute_psql_command(ctx, request, database, psql_args)
|
||||
if pager:
|
||||
click.echo_via_pager(result)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,12 @@ from odoo_openupgrade_wizard.tools.tools_system import execute_check_output
|
|||
@versions_options
|
||||
@click.pass_context
|
||||
def pull_submodule(ctx, versions):
|
||||
"""Pull submodule that contains repos.yml file, if define in config.yml"""
|
||||
"""Pull the repos.yml file from a Git repository.
|
||||
|
||||
This command runs `git submodule update --init --recursive`
|
||||
for the submodule that contains your `repos.yml` file.
|
||||
This ensures all nested submodules are also fetched.
|
||||
"""
|
||||
for odoo_version in get_odoo_versions_from_options(ctx, versions):
|
||||
version_cfg = (
|
||||
ctx.obj["config"]["odoo_version_settings"][odoo_version] or {}
|
||||
|
|
|
|||
|
|
@ -13,30 +13,29 @@ from odoo_openupgrade_wizard.tools.tools_system import restore_filestore
|
|||
"--database-path",
|
||||
required=True,
|
||||
type=click.Path(readable=True, resolve_path=True, exists=True),
|
||||
help="Path to the database dump relative project folder.",
|
||||
help="Path to the database dump (inside the environment folder).",
|
||||
)
|
||||
@click.option(
|
||||
"--database-format",
|
||||
required=True,
|
||||
type=click.Choice(("c", "d", "t", "p")),
|
||||
default="c",
|
||||
help="Database format (see pg_dump options): "
|
||||
"custom format compressed (c), directory (d), tar file (t),"
|
||||
" plain sql text (p).",
|
||||
help="Format of the database dump: custom (c), directory (d), tar (t), "
|
||||
"or plain SQL (p).",
|
||||
)
|
||||
@click.option(
|
||||
"--filestore-path",
|
||||
required=True,
|
||||
type=click.Path(readable=True, resolve_path=True, exists=True),
|
||||
help="Path to the filestore backup.",
|
||||
help="Path to the filestore backup (inside the environment folder).",
|
||||
)
|
||||
@click.option(
|
||||
"--filestore-format",
|
||||
required=True,
|
||||
type=click.Choice(("d", "t", "tgz")),
|
||||
default="tgz",
|
||||
help="Filestore format: directory (d), tar file (t), "
|
||||
"tar file compressed with gzip (tgz)",
|
||||
help="Format of the filestore: directory (d), tar (t), or gzip-compressed "
|
||||
"tar (tgz).",
|
||||
)
|
||||
@click.pass_context
|
||||
def restoredb(
|
||||
|
|
@ -47,7 +46,13 @@ def restoredb(
|
|||
filestore_path,
|
||||
filestore_format,
|
||||
):
|
||||
"""Restore an Odoo database and associated filestore."""
|
||||
"""Restore a database and its associated filestore.
|
||||
|
||||
This command restores a PostgreSQL database and its matching Odoo
|
||||
filestore into the current OOW environment. The filestore and
|
||||
database dump must be accessible from within the environment directory
|
||||
so that the Docker container can read them during restore.
|
||||
"""
|
||||
|
||||
database_path = Path(database_path)
|
||||
filestore_path = Path(filestore_path)
|
||||
|
|
@ -57,7 +62,7 @@ def restoredb(
|
|||
if not str(database_path).startswith(str(absolute_env_folder_path)):
|
||||
ctx.fail(
|
||||
"database-path should be inside the project path to allow "
|
||||
"postgresql to read to it."
|
||||
"PostgreSQL to read it."
|
||||
)
|
||||
|
||||
# Restore the database
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
|
|||
"-i",
|
||||
"--init-modules",
|
||||
type=str,
|
||||
help="List of modules to install. Equivalent to -i odoo options.",
|
||||
help="List of modules to install. Equivalent to -i Odoo options.",
|
||||
)
|
||||
@click.option(
|
||||
"-u",
|
||||
"--update-modules",
|
||||
type=str,
|
||||
help="List of modules to update. Equivalent to -u odoo options.",
|
||||
help="List of modules to update. Equivalent to -u Odoo options.",
|
||||
)
|
||||
@click.option(
|
||||
"-e",
|
||||
|
|
@ -41,7 +41,7 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
|
|||
type=click.Choice(["regular", "openupgrade"]),
|
||||
help="Force to use an openupgrade (OCA/openupgrade)"
|
||||
" or a regular (odoo/odoo or OCA/OCB) base code when running odoo."
|
||||
" Let empty to use the defaut execution of the migration step.",
|
||||
" Leave empty to use the default execution of the migration step.",
|
||||
)
|
||||
@click.pass_context
|
||||
def run(
|
||||
|
|
@ -54,6 +54,14 @@ def run(
|
|||
update_modules,
|
||||
execution_context,
|
||||
):
|
||||
"""Run Odoo for a specific migration step.
|
||||
|
||||
The database will be created if it doesn't already exist. Unless the
|
||||
`stop-after-init` flag is used, the Odoo instance will be available
|
||||
on your host at the following URL: http://localhost:9069
|
||||
(port depends on the `host_odoo_xmlrpc_port` setting in your
|
||||
`config.yml` file).
|
||||
"""
|
||||
migration_step = get_migration_step_from_options(ctx, step)
|
||||
ensure_database(ctx, database, state="present")
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
|
|||
@demo_option
|
||||
@click.pass_context
|
||||
def upgrade(ctx, first_step, last_step, database, with_demo):
|
||||
"""Performs the full db migration across all steps.
|
||||
|
||||
For each step, this will:
|
||||
|
||||
1. Run `pre-migration.sql` scripts.
|
||||
|
||||
2. Apply "update all" (in an upgrade or update context).
|
||||
|
||||
3. Run `post-migration.py` scripts via XML-RPC/Odoo shell (via `odoorpc`).
|
||||
"""
|
||||
migration_steps = get_migration_steps_from_options(
|
||||
ctx, first_step, last_step
|
||||
)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ def get_odoo_run_command(migration_step: dict) -> str:
|
|||
|
||||
|
||||
def get_odoo_folder(
|
||||
migration_step: dict, execution_context: str = False
|
||||
migration_step: dict, execution_context: str = None
|
||||
) -> str:
|
||||
"""return the main odoo folder, depending on the migration step.
|
||||
(./src/odoo, ./src/openupgrade, ...)"""
|
||||
|
|
@ -100,7 +100,7 @@ def skip_addon_path(migration_step: dict, path: Path) -> bool:
|
|||
|
||||
|
||||
def get_server_wide_modules_upgrade(
|
||||
migration_step: dict, execution_context: str = False
|
||||
migration_step: dict, execution_context: str = None
|
||||
) -> list:
|
||||
"""return a list of modules to load, depending on the migration step."""
|
||||
if (
|
||||
|
|
@ -126,7 +126,7 @@ def get_upgrade_analysis_module(migration_step: dict) -> str:
|
|||
def generate_records(odoo_instance, migration_step: dict):
|
||||
logger.info(
|
||||
"Generate Records in version %s..."
|
||||
" (It can take a while)" % (migration_step["version"])
|
||||
" (This may take a while)" % (migration_step["version"])
|
||||
)
|
||||
if migration_step["version"] < 14.0:
|
||||
wizard = odoo_instance.browse_by_create(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/13.0/setup/package.dfsrc
|
||||
FROM debian:buster
|
||||
|
||||
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y locales && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/14.0/setup/package.dfsrc
|
||||
FROM debian:buster
|
||||
|
||||
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y locales && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/15.0/setup/package.dfsrc
|
||||
FROM debian:buster
|
||||
|
||||
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y locales && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
# <OOW> : Copy of https://github.com/odoo/odoo/blob/16.0/setup/package.dfsrc
|
||||
FROM debian:buster
|
||||
|
||||
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y locales && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def copydb(ctx, source, dest):
|
|||
shutil.rmtree(dest_path, ignore_errors=True)
|
||||
|
||||
# Copy Filestore
|
||||
logger.info(f"Copy filestore of '{source}' into '{dest}' folder ...")
|
||||
logger.info(f"Copy filestore of '{source}' into '{dest}' directory...")
|
||||
shutil.copytree(source_path, dest_path)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ def pull_image(image_name):
|
|||
def build_image(path, tag, buildargs={}):
|
||||
logger.debug(
|
||||
f"Building image named based on {path}/Dockerfile."
|
||||
" This can take a big while ..."
|
||||
" This can take a long time..."
|
||||
)
|
||||
debug_docker_command = f"docker build {path} --tag {tag}"
|
||||
for arg_name, arg_value in buildargs.items():
|
||||
|
|
@ -30,6 +30,7 @@ def build_image(path, tag, buildargs={}):
|
|||
path=str(path),
|
||||
tag=tag,
|
||||
buildargs=buildargs,
|
||||
rm=True,
|
||||
)
|
||||
logger.debug("Image build done.")
|
||||
except docker.errors.BuildError as buildError:
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ def get_odoo_addons_path(
|
|||
ctx,
|
||||
odoo_env_path: Path,
|
||||
migration_step: dict,
|
||||
execution_context: str = False,
|
||||
execution_context: str = None,
|
||||
) -> str:
|
||||
"""Return
|
||||
- addons_path: a list of Path of that contains odoo module
|
||||
|
|
@ -146,12 +146,12 @@ def generate_odoo_command_options(
|
|||
execution_context: str,
|
||||
database: str,
|
||||
demo: bool = False,
|
||||
update: str = False,
|
||||
init: str = False,
|
||||
update: str = None,
|
||||
init: str = None,
|
||||
stop_after_init: bool = False,
|
||||
) -> list:
|
||||
"""
|
||||
Generate Odoo command options as a list of strings to append to any command.
|
||||
Generate Odoo command options as a list of string to append to any command.
|
||||
"""
|
||||
odoo_env_path = get_odoo_env_path(ctx, migration_step["version"])
|
||||
|
||||
|
|
@ -230,8 +230,8 @@ def generate_odoo_command(
|
|||
execution_context: str,
|
||||
database: str,
|
||||
demo: bool = False,
|
||||
update: str = False,
|
||||
init: str = False,
|
||||
update: str = None,
|
||||
init: str = None,
|
||||
stop_after_init: bool = False,
|
||||
shell: bool = False,
|
||||
) -> str:
|
||||
|
|
@ -267,13 +267,13 @@ def run_odoo(
|
|||
ctx,
|
||||
migration_step: dict,
|
||||
detached_container: bool = False,
|
||||
database: str = False,
|
||||
update: str = False,
|
||||
init: str = False,
|
||||
database: str = None,
|
||||
update: str = None,
|
||||
init: str = None,
|
||||
stop_after_init: bool = False,
|
||||
shell: bool = False,
|
||||
demo: bool = False,
|
||||
execution_context: str = False,
|
||||
execution_context: str = None,
|
||||
alternative_xml_rpc_port: int = False,
|
||||
links: dict = {},
|
||||
publish_ports: bool = False,
|
||||
|
|
@ -325,9 +325,9 @@ def run_container_odoo(
|
|||
migration_step: dict,
|
||||
command: str,
|
||||
detached_container: bool = False,
|
||||
database: str = False,
|
||||
database: str = None,
|
||||
alternative_xml_rpc_port: int = False,
|
||||
execution_context: str = False,
|
||||
execution_context: str = None,
|
||||
links: dict = {},
|
||||
publish_ports: bool = False,
|
||||
):
|
||||
|
|
@ -371,7 +371,7 @@ def execute_click_odoo_python_files(
|
|||
database: str,
|
||||
migration_step: dict,
|
||||
python_files: list = [],
|
||||
execution_context: str = False,
|
||||
execution_context: str = None,
|
||||
):
|
||||
if not python_files:
|
||||
# Get post-migration python scripts to execute
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ def get_postgres_container(ctx):
|
|||
# Check if volume exists
|
||||
try:
|
||||
client.volumes.get(volume_name)
|
||||
logger.debug(f"Recovering existing postgres volume: {volume_name}")
|
||||
logger.debug(f"Recovering existing PostgreSQL volume: {volume_name}")
|
||||
except docker.errors.NotFound:
|
||||
logger.info(f"Creating Postgres volume: {volume_name}")
|
||||
client.volumes.create(volume_name)
|
||||
|
|
@ -53,7 +53,7 @@ def get_postgres_container(ctx):
|
|||
for key, value in postgres_extra_settings.items():
|
||||
command += f" -c {key}={value}"
|
||||
|
||||
logger.info(f"Launching Postgres Container. (Image {image_name})")
|
||||
logger.info(f"Launching PostgreSQL Container. (Image {image_name})")
|
||||
|
||||
# base environement variables
|
||||
environments = {
|
||||
|
|
@ -69,7 +69,7 @@ def get_postgres_container(ctx):
|
|||
postgres_version = float(image_name.split(":")[1])
|
||||
except ValueError:
|
||||
raise Exception(
|
||||
"Unable to extract postgres version "
|
||||
"Unable to extract PostgreSQL version "
|
||||
f"from image name {image_name}. "
|
||||
"Define version in the image name is mandatory."
|
||||
)
|
||||
|
|
@ -120,8 +120,8 @@ def execute_sql_file(ctx, database, sql_file):
|
|||
if str(ctx.obj["env_folder_path"]) not in str(sql_file):
|
||||
raise Exception(
|
||||
f"The SQL file {sql_file} is not in the"
|
||||
f" main folder {ctx.obj['env_folder_path']} available"
|
||||
" in the postgres container."
|
||||
f" main directory {ctx.obj['env_folder_path']} available"
|
||||
" in the PostgreSQL container."
|
||||
)
|
||||
relative_path = Path(
|
||||
str(sql_file).replace(str(ctx.obj["env_folder_path"]), ".")
|
||||
|
|
@ -132,7 +132,7 @@ def execute_sql_file(ctx, database, sql_file):
|
|||
"psql --username=odoo --dbname={database} --file {file_path}"
|
||||
).format(database=database, file_path=container_path)
|
||||
logger.info(
|
||||
f"Executing the script '{relative_path}' in postgres container"
|
||||
f"Executing the script '{relative_path}' in PostgreSQL container"
|
||||
f" on database {database}"
|
||||
)
|
||||
exec_container(container, command)
|
||||
|
|
@ -163,7 +163,7 @@ def execute_psql_command(
|
|||
f" {' '.join(psql_args)}"
|
||||
)
|
||||
logger.debug(
|
||||
f"Executing the following command in postgres container\n{command}"
|
||||
f"Executing the following command in PostgreSQL container\n{command}"
|
||||
)
|
||||
docker_result = exec_container(container, command)
|
||||
return docker_result.output.decode("utf-8")
|
||||
|
|
@ -241,7 +241,7 @@ def chown_to_local_user(ctx, filepath: os.PathLike):
|
|||
uid=user_uid, filepath=filepath
|
||||
)
|
||||
logger.debug(
|
||||
f"Executing the following command in postgres container:\n{command}"
|
||||
f"Executing the following command in PostgreSQL container:\n{command}"
|
||||
)
|
||||
chown_result = exec_container(container, command)
|
||||
return chown_result.output.decode("utf8")
|
||||
|
|
@ -277,7 +277,7 @@ def execute_pg_dump(
|
|||
pg_dump_args=pg_dump_args,
|
||||
)
|
||||
logger.debug(
|
||||
f"Executing the following command in postgres container:\n{command}"
|
||||
f"Executing the following command in PostgreSQL container:\n{command}"
|
||||
)
|
||||
pg_dump_result = exec_container(container, command)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ def get_script_folder(ctx, migration_step: dict) -> Path:
|
|||
|
||||
|
||||
def ensure_folder_writable(folder_path: Path):
|
||||
logger.info(f"Make writable the folder '{folder_path}'")
|
||||
logger.info(f"Make writable the directory '{folder_path}'")
|
||||
try:
|
||||
chmod(["--silent", "--recursive", "o+w", str(folder_path)])
|
||||
except ProcessExecutionError:
|
||||
|
|
@ -35,9 +35,9 @@ def ensure_folder_exists(
|
|||
- a log is done at INFO level.
|
||||
"""
|
||||
if not folder_path.exists():
|
||||
cmd = ["--parents", folder_path]
|
||||
cmd = ["--mode", mode] + cmd
|
||||
logger.info(f"Creating folder '{folder_path}' ...")
|
||||
cmd = ["-p", folder_path]
|
||||
cmd = ["-m", mode] + cmd
|
||||
logger.info(f"Creating directory '{folder_path}'...")
|
||||
mkdir(cmd)
|
||||
|
||||
if git_ignore_content:
|
||||
|
|
@ -90,7 +90,7 @@ def git_aggregate(folder_path: Path, config_path: Path, jobs: int):
|
|||
jobs=jobs,
|
||||
dirmatch=None,
|
||||
do_push=False,
|
||||
expand_env=True,
|
||||
expand_env=False,
|
||||
env_file=None,
|
||||
force=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "odoo-openupgrade-wizard"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
description = "CLI tool to manage Odoo Major Upgrades"
|
||||
authors = [
|
||||
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
|
||||
|
|
@ -64,7 +64,6 @@ pylint = "*"
|
|||
tox = "*"
|
||||
towncrier = "*"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ def move_to_test_folder():
|
|||
if os.getcwd().endswith("tests/data/output"):
|
||||
return
|
||||
test_folder_path = Path("tests/data/output")
|
||||
mkdir([test_folder_path, "--parents"])
|
||||
mkdir(["-p", test_folder_path])
|
||||
os.chdir(test_folder_path)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user