Maybe not so frequent, but interesting anyway. π€·
Table of contents
- Can I have my own private template?
- Can I use environments for what they're not?
- How can I run a Posbox/IoT box service for development?
- How can I whitelist a service and allow external access to it?
- How do I develop for an external repo, such as OCA?
- How to bootstrap the global inverse proxy?
- How to change report fonts?
- How to get proper assets when printing reports?
- How to have good QA and test in my CI with Doodba?
- This project is too opinionated, but can I question any of those opinions?
- Where are screencasts and screenshots of my failed E2E tests?
- How to use with podman?
- Why pre-commit fails each time I copy or update the template?
- Why XML is broken after running pre-commit?
- Why is Odoo saying that its database is not initialized?
- Why do I get a "Connection Refused" error when trying to lauch the VSCode Firefox JS Debugger?
- Why don't I see my Firefox extensions while debugging?
- Why do I get a "Connection Refused" error when trying to lauch the VSCode Chrome JS Debugger?
- Why can't Firefox load the page after I start a debugging session?
- Why won't my program stop on the specified breakpoints when using Firefox?
- When upgrading from an old template, prettier fails badly. How to update?
- When upgrading from an old template, pre-commit fails to install. What can I do?
- When upgrading from an old template, copier fails with 'Invalid answer "None"'. How to update?
Yes, and thanks to Copier, you can combine both in the same subproject.
Just make sure to use a separate answers file so both don't mix:
# For the 1st copy
copier --answers-file .copier-answers.private.yml copy gh:Tecnativa/private-template .
# For updates
copier --answers-file .copier-answers.private.yml update .
Check Copier docs for more details.
You want to know if you can use devel.yaml
to serve a production instance?
Wel... yes, you can, but it's not recommended nor supported.
Posbox has special needs that are not useful for most projects, and is quite tightly related to specific hardware and peripherals, so it makes not much sense to ship it by default in this template.
However, for testing connection issues, developing, etc., you might want to boot a resource-limited posbox instance imitation.
The best you can do is buy a Posbox/IoT box and peripherals and use it, but for quick tests that do not involve specific hardware, you can boot it with Doodba by:
- Add the
apt
dependencyusbutils
(which containslsusb
binary). - Add the
pip
dependenciesevdev
andnetifaces
. - Add a
posbox
container, which:- Can read usb devices, privileged.
- Loads at boot all required
hw_*
addons, except forhw_posbox_upgrade
. - Exposes a port that doesn't conflict with Odoo, such as
8070
i.e.
Example patch
diff --git a/devel.yaml b/devel.yaml
index e029d48..2f800de 100644
--- a/devel.yaml
+++ b/devel.yaml
@@ -15,7 +15,7 @@ services:
PORT: "6899 8069"
TARGET: odoo
- odoo:
+ odoo: &odoo
extends:
file: common.yaml
service: odoo
@@ -53,6 +53,21 @@ services:
# XXX Odoo v8 has no `--dev` mode; Odoo v9 has no parameters
- --dev=reload,qweb,werkzeug,xml
+ posbox:
+ <<: *odoo
+ ports:
+ - "127.0.0.1:8070:8069"
+ privileged: true
+ networks: *public
+ volumes:
+ - ./odoo/custom:/opt/odoo/custom:ro,z
+ - ./odoo/auto/addons:/opt/odoo/auto/addons:rw,z
+ - /dev/bus/usb
+ command:
+ - odoo
+ - --workers=0
+ - --load=web,hw_proxy,hw_posbox_homepage,hw_scale,hw_scanner,hw_escpos,hw_blackbox_be,hw_screen
+
db:
extends:
file: common.yaml
diff --git a/odoo/custom/dependencies/apt.txt b/odoo/custom/dependencies/apt.txt
index 8b13789..e32891b 100644
--- a/odoo/custom/dependencies/apt.txt
+++ b/odoo/custom/dependencies/apt.txt
@@ -1 +1 @@
+usbutils
diff --git a/odoo/custom/dependencies/pip.txt b/odoo/custom/dependencies/pip.txt
index e69de29..6eef737 100644
--- a/odoo/custom/dependencies/pip.txt
+++ b/odoo/custom/dependencies/pip.txt
@@ -0,0 +1,2 @@
+evdev
+netifaces
Once you apply those changes, to use it:
invoke img-build --pull
to install the new dependencies.invoke start
to start all services.- Visit
http://localhost:8070
to see the posbox running. - Visit
http://localhost:${ODOO_MAJOR}069
to see Odoo (e.g.:$ODOO_MAJOR
is14
if deploying Odoo 14.0). - Install
point_of_sale
in Odoo. - Configure the POS in Odoo to connect to Posbox in
localhost:8070
.
Of course this won't be fully functional, but it will give you an overview on the posbox stuff.
Beware about possible mixed content errors.
This can become useful when you have isolated environments (like in devel.yaml
and
test.yaml
by default) but you need to allow some external API access for them. I.e.,
you could use Google Fonts API for your customer's reports, and those reports would take
forever and end up rendering badly in staging environments.
In such case, we recommend using the tecnativa/whitelist image. Read its docs there.
You can use the same subproject used to deploy to production.
However, you might find this pattern useful:
- Have your own "development-only subproject". One per Odoo version.
- Add the repo there to
addons.yaml
. For example, addserver-tools: ["*"]
to develop OCA's server-tools. - Download code as usual.
- Develop.
- Push the PR to Github.
- Open your production deployment and add that PR to
repos.yaml
.
This is needed for testing and production environments to be reachable.
Our supported proxy is Traefik. There must be one in each node.
To have it, use this inverseproxy.yaml
file:
Traefik v1 docker compose
version: "2.1"
services:
proxy:
image: docker.io/traefik:1.6-alpine
networks:
shared:
private:
public:
volumes:
- acme:/etc/traefik/acme:rw,Z
ports:
- "80:80"
- "443:443"
depends_on:
- dockersocket
restart: unless-stopped
privileged: true
tty: true
command:
- --ACME.ACMELogging
- [email protected]
- --ACME.EntryPoint=https
- --ACME.HTTPChallenge.entryPoint=http
- --ACME.OnHostRule
- --ACME.Storage=/etc/traefik/acme/acme.json
- --DefaultEntryPoints=http,https
- --EntryPoints=Name:http Address::80 Redirect.EntryPoint:https
- --EntryPoints=Name:https Address::443 TLS
- --LogLevel=INFO
- --Docker
- --Docker.EndPoint=http://dockersocket:2375
- --Docker.ExposedByDefault=false
- --Docker.Watch
dockersocket:
image: tecnativa/docker-socket-proxy
privileged: true
networks:
private:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
CONTAINERS: 1
NETWORKS: 1
SERVICES: 1
SWARM: 1
TASKS: 1
restart: unless-stopped
networks:
shared:
internal: true
driver_opts:
encrypted: 1
private:
internal: true
driver_opts:
encrypted: 1
public:
volumes:
acme:
Then boot it up with:
docker compose -p inverseproxy -f inverseproxy.yaml up -d
This will intercept all requests coming from port 80 (HTTP) and redirect them to port 443 (HTTPS), it will download and install required TLS certificates from Let's Encrypt whenever you boot a new instance, add the required proxy headers to the request, and then redirect all traffic to/from odoo automatically.
It includes a security-enhaced proxy to reduce attack surface when listening to the Docker socket.
This allows you to:
- Have multiple domains for each Odoo instance.
- Have multiple Odoo instances in each node.
- Add an TLS layer automatically and for free.
Doodba ships Liberation fonts as defaults.
If you want to make another font package available, just add it to
[apt.txt
][dependencies] (if it's a normal Debian package) or install it in a [custom
build script][build.d] called i.e. build.d/200-custom-fonts
(if you need to install it
in a more complex way).
If, in addition to that, you want those fonts to be the defaults, then add one (or more) of these build arguments:
FONT_MONO
FONT_SANS
FONT_SERIF
Make sure there's a ir.config_parameter
called report.url
with the value
http://localhost:8069
.
Inside this image, there's the /qa
folder, which provides some necessary plumbing to
perform quality assurance and continous integration if you use [doodba-qa][], which is a
separate (but related) project with that purpose.
Go there to get more instructions.
Of course. There's no guarantee that we will like it, but please do it. π
Starting with Odoo (and Doodba) 13.0, when you're in [the devel environment][development] and run some E2E test (tours, JS tests...) that fails, Odoo will output screenshots and screencasts automatically. These are very useful for debugging.
You can find them in the ./odoo/auto/test-artifacts
directory in your development
host. No need to sniff around inside the container to find them.
In Odoo (and Doodba) 12.0, the screencasts and screenshots feature is also supported,
but it is less intuitive: just apply this patch to your devel.yaml
file:
diff --git a/devel.yaml b/devel.yaml
index 2026e7c..d4e5a68 100644
--- a/devel.yaml
+++ b/devel.yaml
@@ -60,6 +60,7 @@ services:
- --limit-time-real=9999999
- --workers=0
- --dev=reload,qweb,werkzeug,xml
+ - --logfile=/opt/auto/test-artifacts/odoo.log
db:
extends:
You'll find Odoo logs in ./odoo/auto/test-artifacts/odoo.log
file, and screencasts and
screenshots will be around with some weird names. As a side effect, your container will
output no logs to the console.
Since this is an awkward side effect of that setting, we're not shipping that by default.
Podman 4+ is supported for development, provided you follow these instructions.
Example usage:
# Install dependencies
sudo dnf -y install podman podman-docker docker-compose
# Make sure podman works
podman run --rm hello-world
# Install rootless podman backend socket replacement
systemctl enable --user --now podman.socket
# Instruct docker clients to connect to podman backend
export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock
# Instruct git-aggregator to use inner UID and GID 0, which podman will map to your user
export DOODBA_GITAGGREGATE_UID=0 DOODBA_GITAGGREGATE_GID=0 DOODBA_UMASK=22
Once all that is done, continue with normal workflow on that terminal.
Add those exports to your bash profile to avoid repeating them for each terminal. If you
use fish
, it's easier:
# Fish-only syntax to save all those exports permanently
set --universal --export DOCKER_HOST unix:///run/user/(id -u)/podman/podman.sock
set --universal --export DOODBA_GITAGGREGATE_UID 0
set --universal --export DOODBA_GITAGGREGATE_GID 0
set --universal --export DOODBA_UMASK 22
Then continue with the instructions for daily usage.
We format here YAML files using Prettier inside pre-commit.
However, when the template is generated, you have a lot of chances that your YAML files are badly formatted. For instance, depending on the length of you alternate domains, Traefik rules might be longer or shorter, triggering a different reformat on each project, or on each update. That is expected good behavior.
Also, the way Copier formats your .copier-answers.yml
file almost always violates
Prettier's rules.
So, if you find out that after generating the project for the 1st time, or after updating it, it fails pre-commit validations, don't worry about that. Just let pre-commit reformat your files in next commit, and commit again.
Quick dirty recipe:
copier --force update
git add .
pre-commit run
git add .
git commit -m 'Update from template'
Doodba Copier Template enables Prettier as a
pre-commit formatter for many file formats. One of these is
XML, and we configure Prettier with xmlWhitespaceSensitivity: "ignore"
. This is like
telling Prettier: "do whatever you need with XML whitespace to prettify XML files".
We do this because most times XML whitespace is meaningless, and prettifying a file without changing whitespace limits a lot what Prettier can do. However, keep in mind that in some cases, it can be meaningful.
We sometimes use XML in Odoo to generate HTML. In HTML, whitespace matters at least in these cases:
- Inside
the
<pre>
element. - When any element uses
the CSS
white-space
style with certain values.
So, if you see that after running pre-commit
some HTML is broken, this is possibly the
cause.
Our recommendation is that, at least, before you run it for the 1st time, search <pre
(literally) among your private modules, and in case you find any, be careful about what
Prettier does with them.
If you install Fish, you can run these commands to find those dangerous things. If one
fails with No matches for wildcard
, it means there are no files to check and thus you
can ignore that error:
cd $project_root/odoo/custom/src/private
fish -c 'grep "<pre" **.{xml,html}'
fish -c 'grep -E "white-space:\s*(pre|break-spaces)" **.{less,sass,scss,css}'
You can wrap any XML code among ignore tags to tell Prettier "don't touch this":
<!-- prettier-ignore-start -->
<pre>
________________
| |
| DOODBA |
| RULEZ! |
|______________|
(\_/) ||
(β’γ
β’) ||
/ γ γ₯
</pre>
<!-- prettier-ignore-end -->
You can also replace our default for xmlWhitespaceSensitivity: "strict"
inside your
.prettierrc.yml
file.
This is a common problem within the development workflow. From Odoo 12.0, the database needs to be initialized by hand. You can know that you're facing this problem if you see in Odoo's logs something like this:
2020-06-09 10:24:26,715 1 ERROR ? odoo.modules.loading: Database devel not initialized, you can force it with `-i base`
2020-06-09 10:25:26,781 1 ERROR devel odoo.sql_db: bad query: SELECT latest_version FROM ir_module_module WHERE name='base'
ERROR: relation "ir_module_module" does not exist
LINE 1: SELECT latest_version FROM ir_module_module WHERE name='base...
^
You can do as the log is clearly telling you to do (side note: READ THE LOGS! π):
docker compose run --rm odoo --stop-after-init -i base
invoke restart
Or you can use the resetdb
task to reset your devel
database:
invoke resetdb
If you use this method, Odoo will have 2 databases created. You should use the one
called devel
; the other one is just a cache, so the next time you run this command
it's faster.
This is just a helper over these tools, which you might want to use directly instead:
When using Firefox as the debugging browser, this may be happening because the path for its executable is misconfigured.
To fix this, change the firefoxExecutable
variable for the
VS Code Debugger for Firefox
extension under Settings to your Firefox executable path. To find it, you can run:
which firefox
Then, add the following to your global settings.json
file:
{
// ...
"firefox.executable": "/usr/bin/firefox"
// ...
}
Firefox may load a different user profile than your personal one.
To fix that, add the following to your global settings.json
file:
{
// ...
"firefox.profile": "default-release"
// ...
}
Notes:
- Your profile might be named differently. You can visit
about:profiles
from firefox to list them. - The extension is in reality using a temporary copy of that profile, so any changes you
do to it won't be saved unless you configure it with
"firefox.keepProfileChanges": true
. If you enable that option, you may prefer using a profile named differently than your default one, so you can have 2 Firefox instances running in parallel and don't need to stop Firefox to restart it again in debug mode.
When using Chrome as the debugging browser, this may be happening because the path for its executable is misconfigured.
To fix this, you must have either Chrome or Chromium installed in your system.
The Chrome executable will be selected by default and, if not installed, Chromium will
be selected. Make sure you have the respective executable in your $PATH
.
It is possible that the page is not ready yet. Wait a couple of seconds and reload.
When debugging, you must have debug=assets
in your Odoo URL. By default, when you
launch a debugging session, VSCode will open you browser in a new window with the
correct URL. However, if you need to log in, you loose that URL. To avoid that, make
sure you are not losing your cookies each time you reload a debugging session. (See
Why don't I see my Firefox extensions while debugging?
for how to set up your Firefox debugging profile)
Whether it was prettier, npm, nodejs or whoever else, the fact is that recently there happened a prettiermageddon.
When you're updating from an older template to a newer, Copier will try to produce a vanilla project with the old template before updating it, to be able to extract a smart diff and apply the required changes to your subproject.
Since old versions of the template are broken due to this prettier problem, you cannot update anymore. Well, here's the workaround:
-
Indicate to nodeenv that your default nodejs version is 14.14.0 by creating a file in
~/.nodeenvrc
with the following contents. This will avoid the problem of prettier being unable to install:[nodeenv] node = 14.14.0
-
Update to latest template skipping
prettier
hook. This will avoid the problem of prettier + plugin-xml being unable to execute, even if properly installed:env SKIP=prettier copier update
Once all your doodba subprojects are on template v2.5.0 or later, you won't need the
~/.nodeenvrc
anymore (hopefully) and you can safely delete it, as node version is
pinned there and we install prettier from
their new specific pre-commit repo.
Due to the
latest updates to the pip
dependency resolver,
some packages fail to install.
As with the recent prettiermageddon, when you're updating from an older template to a newer, Copier will try to produce a vanilla project with the old template before updating it, to be able to extract a smart diff and apply the required changes to your subproject.
Since old versions of the template might be broken if you are running the latest pip
version, you cannot update anymore. Where is what you can do to avoid it:
-
Since
pre-commit
manages it's dependencies withpython-virtualenv
, you can indicate which version of pip it should use. There are several ways of doing it, but the easiest is with an environment variable. Just passVIRTUALENV_PIP=20.2
before any command that fails due to this problem. For example, when running a copier update:env VIRTUALENV_PIP=20.2 copier update
Once all your doodba subprojects are on template v2.6.1 or later, you shouldn't have this problem, as the pre-commit hook's versions and dependencies where tailored to work with these new constraints.
When you're updating from an older template to a newer, Copier will try to produce a vanilla project with the old template before updating it, to be able to extract a smart diff and apply the required changes to your subproject.
Since old versions of the template are broken due to this copier problem, you cannot update anymore. Well, here's the workaround:
- Launch 'recopy':
copier recopy --trust -f .
- Save the name of the question that gives the problem (for example 'odoo_oci_image')
- Launch 'recopy' again but with an empty string as the default value for the
problematic question:
copier recopy --trust -f -d odoo_oci_image='' .
- Repeat the steps expanding in point 4 with as many questions as you need:
-d var1='' -d var2=[] ...
For example, getting this error:
copier.errors.InvalidTypeError: Invalid answer "None" of type "<class 'NoneType'>" to question "gitlab_url" of type "str"
You can see the name of the problematic question (gitlab_url) and its type (str).
Normally the conversion would look something like this:
Question Type | New value to use with -d |
---|---|
str | '' |
yaml | {} |
int | 0 |
float | 0 |
json | {} |
bool | false |