gOdoo-cli 1.0.0__tar.gz → 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/PKG-INFO +1 -1
  2. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docs/lifecycle.md +9 -3
  3. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/__about__.py +1 -1
  4. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/upgrade.py +29 -0
  5. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/filestore.py +4 -1
  6. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_upgrade.py +69 -0
  7. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_filestore.py +14 -6
  8. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.agents/skills/godoo-changeset-review/SKILL.md +0 -0
  9. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.agents/skills/godoo-editor-validation/SKILL.md +0 -0
  10. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.agents/skills/godoo-runtime-validation/SKILL.md +0 -0
  11. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.agents/skills/godoo-source-workspaces/SKILL.md +0 -0
  12. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.codecovrc +0 -0
  13. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.dockerignore +0 -0
  14. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.env.sample +0 -0
  15. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.github/FUNDING.yml +0 -0
  16. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.github/workflows/README.md +0 -0
  17. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.github/workflows/quality.yml +0 -0
  18. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.github/workflows/version-bump.yml +0 -0
  19. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.github/workflows/version-publish.yml +0 -0
  20. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.gitignore +0 -0
  21. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.pre-commit-config.yaml +0 -0
  22. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.prettierrc.yml +0 -0
  23. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.vscode/extensions.json +0 -0
  24. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.vscode/settings.json +0 -0
  25. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/.vscode/tasks.json +0 -0
  26. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/AGENTS.md +0 -0
  27. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/LICENSE +0 -0
  28. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/README.md +0 -0
  29. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/.gitkeep +0 -0
  30. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/godoo_test_succ_mod/__init__.py +0 -0
  31. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/godoo_test_succ_mod/__manifest__.py +0 -0
  32. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/godoo_test_succ_mod/models/__init__.py +0 -0
  33. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/godoo_test_succ_mod/tests/__init__.py +0 -0
  34. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/godoo_test_succ_mod/tests/data.py +0 -0
  35. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/addons/godoo_test_succ_mod/tests/test_succ.py +0 -0
  36. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/assets/odoo_logo.png +0 -0
  37. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/config/nginx.conf.template +0 -0
  38. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/config/postgresql.conf +0 -0
  39. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docker/Dockerfile +0 -0
  40. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docker/docker-compose.base.yml +0 -0
  41. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docker/docker-compose.dev.yml +0 -0
  42. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docker/docker-compose.traefik.yml +0 -0
  43. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docker/postgres-init/10-vector.sql +0 -0
  44. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docs/architecture.md +0 -0
  45. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docs/downstream.md +0 -0
  46. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docs/hooks.md +0 -0
  47. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/docs/workspace.md +0 -0
  48. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/makefile +0 -0
  49. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/odoo_manifest.yml +0 -0
  50. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/package-lock.json +0 -0
  51. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/package.json +0 -0
  52. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/pyproject.toml +0 -0
  53. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/scripts/check_docstring_style.py +0 -0
  54. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/scripts/migrations/development/shrink_database.py +0 -0
  55. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/__init__.py +0 -0
  56. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/__main__.py +0 -0
  57. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/__init__.py +0 -0
  58. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/common.py +0 -0
  59. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/configuration.py +0 -0
  60. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/db/__init__.py +0 -0
  61. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/db/archive.py +0 -0
  62. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/db/cli.py +0 -0
  63. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/db/passwords.py +0 -0
  64. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/db/query.py +0 -0
  65. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/db/reset.py +0 -0
  66. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/odoo_bin/__init__.py +0 -0
  67. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/root.py +0 -0
  68. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/rpc/__init__.py +0 -0
  69. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/rpc/cli.py +0 -0
  70. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/rpc/config_parameters.py +0 -0
  71. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/rpc/importer.py +0 -0
  72. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/rpc/modules.py +0 -0
  73. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/rpc/translations.py +0 -0
  74. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/run.py +0 -0
  75. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/__init__.py +0 -0
  76. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/dependencies.py +0 -0
  77. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/init.py +0 -0
  78. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/launch.py +0 -0
  79. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/shell.py +0 -0
  80. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/shell_scripts/odoo_banner.py +0 -0
  81. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/shell_scripts/render_report.py +0 -0
  82. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/runtime/status.py +0 -0
  83. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/test/__init__.py +0 -0
  84. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/test/cli.py +0 -0
  85. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/test/load_data.py +0 -0
  86. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/test/run.py +0 -0
  87. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/workspace/__init__.py +0 -0
  88. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/workspace/common.py +0 -0
  89. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/workspace/configure.py +0 -0
  90. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/workspace/image.py +0 -0
  91. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/workspace/storage.py +0 -0
  92. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/commands/workspace/sync.py +0 -0
  93. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/database/__init__.py +0 -0
  94. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/database/connection.py +0 -0
  95. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/database/postgres.py +0 -0
  96. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/database/settings.py +0 -0
  97. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/database/state.py +0 -0
  98. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/git/__init__.py +0 -0
  99. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/git/git_url.py +0 -0
  100. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/git/repository.py +0 -0
  101. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/helpers/__init__.py +0 -0
  102. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/helpers/hashing.py +0 -0
  103. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/helpers/modules_git.py +0 -0
  104. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/helpers/progress.py +0 -0
  105. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/helpers/system.py +0 -0
  106. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/models/__init__.py +0 -0
  107. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/models/godoo_git_repo.py +0 -0
  108. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/models/godoo_manifest.py +0 -0
  109. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/models/godoo_models.py +0 -0
  110. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/models/godoo_modules.py +0 -0
  111. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/__init__.py +0 -0
  112. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/archive.py +0 -0
  113. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/baseline.py +0 -0
  114. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/dataset.py +0 -0
  115. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/hooks.py +0 -0
  116. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/lifecycle.py +0 -0
  117. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/locks.py +0 -0
  118. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/nginx.py +0 -0
  119. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/odoo.py +0 -0
  120. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/promotion.py +0 -0
  121. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/reset.py +0 -0
  122. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/restore.py +0 -0
  123. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/runtime/status.py +0 -0
  124. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/__init__.py +0 -0
  125. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/editor.py +0 -0
  126. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/git.py +0 -0
  127. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/image.py +0 -0
  128. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/manifest.py +0 -0
  129. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/operations.py +0 -0
  130. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/specifications.py +0 -0
  131. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/storage.py +0 -0
  132. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/src/godoo_cli/workspace/types.py +0 -0
  133. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/__init__.py +0 -0
  134. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_db_archive_cli.py +0 -0
  135. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_db_query_cli.py +0 -0
  136. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_odoo_bin_commands.py +0 -0
  137. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_rpc_commands.py +0 -0
  138. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_runtime_cli.py +0 -0
  139. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_runtime_dependencies.py +0 -0
  140. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_runtime_shell_scripts.py +0 -0
  141. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/commands/test_test_run.py +0 -0
  142. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/conftest.py +0 -0
  143. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/database/test_db_query.py +0 -0
  144. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/database/test_db_reset.py +0 -0
  145. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/database/test_db_restore.py +0 -0
  146. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/git/test_git_url_uri.py +0 -0
  147. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/integration/test_container_contract.py +0 -0
  148. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/integration/test_odoo_integration.py +0 -0
  149. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_archive_crc.py +0 -0
  150. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_baseline_recovery.py +0 -0
  151. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_database_copy.py +0 -0
  152. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_dataset.py +0 -0
  153. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_filestore_copy.py +0 -0
  154. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_hooks.py +0 -0
  155. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_init_hooks.py +0 -0
  156. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_init_policy.py +0 -0
  157. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_lifecycle.py +0 -0
  158. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_lifecycle_service.py +0 -0
  159. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_nginx.py +0 -0
  160. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_nginx_cli.py +0 -0
  161. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_odoo_config_generation.py +0 -0
  162. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_odoo_preflight.py +0 -0
  163. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_odoo_version_compatibility.py +0 -0
  164. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_report_url.py +0 -0
  165. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_reset_baseline.py +0 -0
  166. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_runtime_models.py +0 -0
  167. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_runtime_operations.py +0 -0
  168. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/runtime/test_runtime_source_environment.py +0 -0
  169. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/test_logging.py +0 -0
  170. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_godoo_manifest.py +0 -0
  171. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_workspace.py +0 -0
  172. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_workspace_git.py +0 -0
  173. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_workspace_image.py +0 -0
  174. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_workspace_layout.py +0 -0
  175. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_workspace_runtime_env.py +0 -0
  176. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/tests/workspace/test_workspace_storage.py +0 -0
  177. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/thirdparty/.gitkeep +0 -0
  178. {godoo_cli-1.0.0 → godoo_cli-1.0.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: gOdoo-cli
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Odoo lifecycle, Python dependency preflight, and shared Git workspaces.
5
5
  Project-URL: repository, https://github.com/OpenJKSoftware/gOdoo
6
6
  Author-email: Joshua Kreuder <Joshua_Kreuder@outlook.com>
@@ -112,9 +112,9 @@ filestore, SQL and archive overlays are staged once and reused. Disabling the fu
112
112
  checks. CRC checks detect accidental corruption; they do not establish the archive's origin.
113
113
 
114
114
  On Linux, gOdoo probes one nonempty file before recursive reflink copying, then falls back to rsync or Python copying.
115
- Desktop bind mounts can make many small attachment copies expensive; see
116
- [dataset storage](downstream.md#restore-dataset-storage). Reset baselines can share reflink extents, so logical sizes
117
- may count shared data more than once.
115
+ Rsync shows progress only when stdout is a terminal; diagnostics remain visible in captured output. Desktop bind mounts
116
+ can make many small attachment copies expensive; see [dataset storage](downstream.md#restore-dataset-storage). Reset
117
+ baselines can share reflink extents, so logical sizes may count shared data more than once.
118
118
 
119
119
  The official upgrade client reports phase start and completion or failure without a heartbeat. Child processes retain
120
120
  their native streams. gOdoo forwards SIGINT/SIGTERM, waits for shutdown, and preserves child exit status.
@@ -178,6 +178,12 @@ sequenceDiagram
178
178
  Maintainer->>Maintainer: Review Odoo's report before restoring into a test runtime
179
179
  ```
180
180
 
181
+ Before downloading the official client, `godoo upgrade` logs the modification date and absolute path of the dump
182
+ selected by `-i` / `--dump` and the adjacent `odoo_filestore` directory. Dates include the local timezone offset. The
183
+ filestore stays local for restoring the result. Its directory timestamp reflects changes to immediate entries, not
184
+ changes throughout the attachment tree or proof that the dump and filestore were captured together. Missing metadata
185
+ produces a warning; the official client still owns input validation. Commands without a dump do not log source dates.
186
+
181
187
  HTTPS certificate and hostname verification is enabled by default. `GODOO_UPGRADE_SSL=0` disables verification for both
182
188
  the download and client while retaining HTTPS encryption; use it only for an endpoint whose certificate the host cannot
183
189
  verify.
@@ -1,3 +1,3 @@
1
1
  """Version information."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.0.2"
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import argparse
5
6
  import logging
6
7
  import os
7
8
  import signal
@@ -10,6 +11,7 @@ import subprocess
10
11
  import sys
11
12
  import tempfile
12
13
  from contextlib import suppress
14
+ from datetime import UTC, datetime
13
15
  from pathlib import Path
14
16
  from typing import Annotated, cast
15
17
  from urllib.error import URLError
@@ -24,8 +26,35 @@ LOGGER = logging.getLogger(__name__)
24
26
  UPGRADE_CLIENT_URL = "https://upgrade.odoo.com/upgrade"
25
27
 
26
28
 
29
+ def _log_upgrade_sources(arguments: list[str]) -> None:
30
+ """Log the selected dump and paired local filestore before the client starts."""
31
+ parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False, exit_on_error=False)
32
+ parser.add_argument("-i", "--dump", type=Path)
33
+ try:
34
+ options, _ = parser.parse_known_args(arguments)
35
+ except argparse.ArgumentError:
36
+ # Odoo's client owns argument validation and its error messages.
37
+ return
38
+ if options.dump is None:
39
+ return
40
+
41
+ dump = options.dump.absolute()
42
+ sources = (
43
+ ("Dump change date (upload)", dump),
44
+ ("Filestore change date (local restore)", dump.parent / "odoo_filestore"),
45
+ )
46
+ for label, path in sources:
47
+ try:
48
+ modified_at = datetime.fromtimestamp(path.stat().st_mtime, tz=UTC).astimezone()
49
+ except OSError as error:
50
+ LOGGER.warning("Could not read %s (%s): %s", label, path, error)
51
+ continue
52
+ LOGGER.info("%s: %s (%s)", label, modified_at.isoformat(timespec="seconds"), path)
53
+
54
+
27
55
  def _run_upgrade_client(arguments: list[str]) -> int:
28
56
  """Download and run Odoo's official upgrade client with its arguments."""
57
+ _log_upgrade_sources(arguments)
29
58
  ssl_disabled = os.getenv("GODOO_UPGRADE_SSL") == "0"
30
59
  context = ssl._create_unverified_context() if ssl_disabled else None
31
60
  try:
@@ -85,7 +85,10 @@ def _copy_with_rsync(source: Path, destination: Path) -> tuple[bool, str | None]
85
85
  if not shutil.which("rsync"):
86
86
  return False, "rsync is not available"
87
87
 
88
- command = ["rsync", "-rLpt", "--human-readable", "--info=progress2", f"{source}/", str(destination)]
88
+ command = ["rsync", "-rLpt", "--human-readable"]
89
+ if sys.stdout.isatty():
90
+ command.append("--info=progress2")
91
+ command.extend([f"{source}/", str(destination)])
89
92
  try:
90
93
  process = subprocess.Popen(command, stdout=None, stderr=subprocess.STDOUT)
91
94
  except OSError as error:
@@ -3,10 +3,12 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import importlib
6
+ import logging
6
7
  import os
7
8
  import signal
8
9
  import ssl
9
10
  import sys
11
+ from datetime import UTC, datetime
10
12
  from io import BytesIO
11
13
  from pathlib import Path
12
14
  from unittest.mock import Mock
@@ -194,3 +196,70 @@ def test_upgrade_cli_preserves_nonzero_client_status(monkeypatch: pytest.MonkeyP
194
196
  result = CliRunner().invoke(main_cli(), ["upgrade", "status", "token"])
195
197
 
196
198
  assert result.exit_code == 23, result.output
199
+
200
+
201
+ @pytest.mark.parametrize("dump_option", ["-i", "--dump", "--dump=", "-i-attached"])
202
+ def test_upgrade_logs_source_dates_before_download_and_client(
203
+ monkeypatch: pytest.MonkeyPatch,
204
+ tmp_path: Path,
205
+ caplog: pytest.LogCaptureFixture,
206
+ dump_option: str,
207
+ ) -> None:
208
+ """The actual selected file and paired directory are logged before network work."""
209
+ dataset = tmp_path / "dataset with spaces"
210
+ dataset.mkdir()
211
+ dump = dataset / "source.dump"
212
+ dump.touch()
213
+ filestore = dataset / "odoo_filestore"
214
+ filestore.mkdir()
215
+ os.utime(dump, (1700000000, 1700000000))
216
+ os.utime(filestore, (1600000000, 1600000000))
217
+ monkeypatch.chdir(tmp_path)
218
+ relative_dump = str(dump.relative_to(tmp_path))
219
+ if dump_option == "--dump=":
220
+ selection = [f"--dump={relative_dump}"]
221
+ elif dump_option == "-i-attached":
222
+ selection = [f"-i{relative_dump}"]
223
+ else:
224
+ selection = [dump_option, relative_dump]
225
+ arguments = ["test", *selection, "--future-official-option", "value", "-x"]
226
+ caplog.set_level(logging.INFO, logger=upgrade_command.LOGGER.name)
227
+
228
+ def download(*_args: object, **_kwargs: object) -> BytesIO:
229
+ assert (
230
+ f"Dump change date (upload): {datetime.fromtimestamp(1700000000, UTC).astimezone().isoformat()} ({dump})"
231
+ in caplog.text
232
+ )
233
+ assert (
234
+ f"Filestore change date (local restore): {datetime.fromtimestamp(1600000000, UTC).astimezone().isoformat()} ({filestore})"
235
+ in caplog.text
236
+ )
237
+ return BytesIO(b"official client")
238
+
239
+ child = Mock(return_value=Mock(wait=lambda: 0, pid=42))
240
+ monkeypatch.setattr(upgrade_command, "urlopen", download)
241
+ monkeypatch.setattr(upgrade_command.subprocess, "Popen", child)
242
+
243
+ assert upgrade_command._run_upgrade_client(arguments) == 0
244
+ assert child.call_args.args[0][2:] == arguments
245
+
246
+
247
+ def test_upgrade_missing_source_metadata_does_not_replace_client_validation(
248
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path, caplog: pytest.LogCaptureFixture
249
+ ) -> None:
250
+ """Missing timestamps produce warnings while the official client keeps ownership."""
251
+ dump = tmp_path / "missing.dump"
252
+ monkeypatch.setattr(upgrade_command, "urlopen", lambda *_args, **_kwargs: BytesIO(b""))
253
+ monkeypatch.setattr(upgrade_command, "_run_process", lambda *_args, **_kwargs: 23)
254
+
255
+ assert upgrade_command._run_upgrade_client(["test", "-i", str(dump)]) == 23
256
+ assert f"Could not read Dump change date (upload) ({dump})" in caplog.text
257
+ assert f"Could not read Filestore change date (local restore) ({tmp_path / 'odoo_filestore'})" in caplog.text
258
+
259
+
260
+ @pytest.mark.parametrize("arguments", [["status", "token"], ["test", "--dbname", "database"], ["test", "-i"]])
261
+ def test_upgrade_skips_source_logging_without_a_dump(arguments: list[str], caplog: pytest.LogCaptureFixture) -> None:
262
+ """Database mode, status, and malformed dump options stay with the official client."""
263
+ caplog.set_level(logging.INFO, logger=upgrade_command.LOGGER.name)
264
+ upgrade_command._log_upgrade_sources(arguments)
265
+ assert not caplog.records
@@ -235,14 +235,17 @@ def _fake_rsync(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, *, status: int)
235
235
  rsync.write_text(
236
236
  "#!/bin/sh\n"
237
237
  'printf \'%s\\n\' "$@" > "$GODOO_RSYNC_ARGS"\n'
238
- "printf '12%%\\rdiagnostic one\\n34%%\\rdiagnostic two\\n56%%\\r78%%\\n'\n"
238
+ 'if [ "$3" = "--info=progress2" ]; then\n'
239
+ " printf '12%%\\rdiagnostic one\\n34%%\\rdiagnostic two\\n56%%\\r78%%\\n'\n"
240
+ " shift\n"
241
+ "fi\n"
239
242
  "printf 'rsync diagnostic\\n' >&2\n"
240
243
  f"if [ {status} -ne 0 ]; then\n"
241
- ' mkdir -p "$5"\n'
242
- ' printf stale > "$5/stale"\n'
244
+ ' mkdir -p "$4"\n'
245
+ ' printf stale > "$4/stale"\n'
243
246
  f" exit {status}\n"
244
247
  "fi\n"
245
- 'cp -RL "$4/." "$5"\n'
248
+ 'cp -RL "$3/." "$4"\n'
246
249
  f"exit {status}\n",
247
250
  encoding="utf-8",
248
251
  )
@@ -252,12 +255,16 @@ def _fake_rsync(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, *, status: int)
252
255
  return rsync
253
256
 
254
257
 
258
+ @pytest.mark.parametrize("interactive", [False, True])
255
259
  def test_rsync_copy_passes_output_directly_to_stdout_and_materializes_symlinks(
256
260
  tmp_path: Path,
257
261
  monkeypatch: pytest.MonkeyPatch,
258
262
  caplog: pytest.LogCaptureFixture,
259
263
  capfdbinary: pytest.CaptureFixture[bytes],
264
+ interactive: bool,
260
265
  ) -> None:
266
+ monkeypatch.setattr("godoo_cli.runtime.filestore.sys.stdout.isatty", lambda: interactive)
267
+ monkeypatch.setattr("godoo_cli.runtime.filestore.sys.stderr.isatty", lambda: not interactive)
261
268
  source = tmp_path / "source"
262
269
  source.mkdir()
263
270
  (source / "kept").write_text("original")
@@ -277,13 +284,14 @@ def test_rsync_copy_passes_output_directly_to_stdout_and_materializes_symlinks(
277
284
  assert (tmp_path / "rsync-args").read_text().splitlines() == [
278
285
  "-rLpt",
279
286
  "--human-readable",
280
- "--info=progress2",
287
+ *(["--info=progress2"] if interactive else []),
281
288
  f"{source}/",
282
289
  str(destination),
283
290
  ]
284
291
  assert "-a" not in (tmp_path / "rsync-args").read_text().splitlines()
285
292
  captured = capfdbinary.readouterr()
286
- assert captured.out == b"12%\rdiagnostic one\n34%\rdiagnostic two\n56%\r78%\nrsync diagnostic\n"
293
+ progress = b"12%\rdiagnostic one\n34%\rdiagnostic two\n56%\r78%\n" if interactive else b""
294
+ assert captured.out == progress + b"rsync diagnostic\n"
287
295
  assert captured.err == b""
288
296
  assert not caplog.records
289
297
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes