Workstation profiles, pulling and publishing
A profile on a developer workstation binds one customer instance on a registered environment to one local instance on this workstation. Everything else on this page is something you do to a profile.
It is a different thing from a workspace profile, which sets how the code editor in the browser opens on a server. The two share a word and nothing else.
In the console they are under Developer, a section that appears only on a workstation.
Creating one
$ ohm dev add --name acme-live --environment acme --instance fanes.example.com --git-token--git-token with no value prompts without echo. It is your token for the add-on repositories,
not the customer's, and it is the only secret a profile holds. Create the profile without one using
--no-git-token; a pull then refuses until you supply it.
| Option | What it decides |
|---|---|
--expires <days> | Days until the profile expires. Default 30 |
--no-expiry | The customer's data stays here indefinitely |
--no-purge | Report the expiry rather than acting on it |
--allow-restricted | Permit a Restricted source onto this machine |
--debug, --debug-mode | Normal, Debug or DebugReload |
--ide vscode|pycharm | Overrides the workstation default |
--pull | Pull as soon as the profile exists |
Change any of them later with ohm dev set.
$ ohm dev listPulling
$ ohm dev pull acme-live --switch --openThe pull downloads the customer's archive through that server's own route, imports it with the Development preset, and neutralises the restored database. In order, with what stops it:
- Identity. The source server must still report the identity it had when the profile was created. A cloned or replaced server is refused rather than silently pulled from.
- PostgreSQL majors. A local major older than the source's is refused unless you pass
--allow-older-postgres, and the message names both. Newer or equal is fine - a plain dump restores forward. - Classification. A
Restrictedsource needs--allow-restrictedon the profile.ConfidentialandRestrictedare both refused on a disk that was not proven encrypted. - Which archive.
--backup latest(the default) takes the newest one already on the customer;--backup freshasks the customer server to take one now and waits for it, up to--fresh-timeoutminutes (default 120); or name an archive path on the source. - Room to land it. The manifest is read before the transfer, and the pull refuses when the archive plus its extracted size would not fit.
- The transfer resumes where it left off if it drops, and the checksum is compared on arrival.
- Your local work is checked first. On a re-pull, every module checkout is inspected. Anything
modified, untracked or not pushed stops the pull, naming the modules and the exact state -
"3 modified, 1 untracked, 2 commits not on origin".
--discard-changesoverrides it, and means what it says.
Step 7 is the only thing standing between a re-pull and your uncommitted work. It is a real check against the working trees, not a timestamp - but it can only see the checkouts. Anything you changed outside a module repository is not covered by it.
Neutralisation is not optional
Every workstation restore is neutralised on top of the Development preset, and there is no option
that turns it off. It disables payment providers, deletes API keys, disables OAuth providers,
clears IAP tokens, takes delivery carriers out of production mode, clears Google and Microsoft
calendar tokens, deactivates social accounts, and points web.base.url at the local instance.
Mail is already disabled by the preset, pointed at an invalid server.
Every statement is guarded by whether the table or column exists, so a database missing a module does not fail the restore, and the job log lists what actually ran. Odoo's own neutralised banner is switched on explicitly, so the database says what it is from inside the UI too.
User passwords are kept, so the customer's own users sign in with the customer's passwords. For you,
the pull adds an Odoo administrator account to the restored database and prints its password and
authenticator (TOTP) secret once, at the end of the pull. The account's login is named in the
result of that job on the Jobs page ("Sysadmin user '...' created in database '...'"). Missed
the password? Create a new one with ohm instance database sysadmin create.
Working on it
$ ohm dev statusThe state of every add-on checkout: what is modified, untracked, or sitting on commits that are not on the origin. This is the same check the pull and the purge run, so what it says is what will stop them.
$ ohm dev openOpens the editor on the profile's container. --print writes the launch command and the files
instead of starting anything, which is what you want when the editor lives outside this machine or
you are putting the invocation in a script.
Debugging runs the instance under debugpy: set it per profile with --debug or pick the mode with
--debug-mode Normal|Debug|DebugReload.
Starting a new add-on
$ ohm dev repo create --name acme-feature --module acme_feature --workspace acme --summary "Feature work"Creates the repository and scaffolds a module into it. --name is the repository's name and
--module the technical name of the module, which is the repository's name when you leave it out.
--workspace is the account or organisation at your git provider that the repository is created
under; it has nothing to do with workspace profiles. The repository is private by default, and
--public is the only way to change that. Use --no-scaffold for an empty repository with no
module written or enabled.
The names are checked before anything is created:
- A repository name takes letters, digits, dots, hyphens and underscores only, at most 100
characters, and is never
.or... - A module name takes letters, digits and underscores only and starts with a letter or an
underscore, because Odoo imports it under that name. A repository called
acme-featuretherefore needs--modulewith a name such asacme_feature.
A scaffold never goes into a folder that is already there: when the instance's add-ons already hold
a folder of the repository's name, the repository is created but nothing is scaffolded into it, and
the command says so. Move or rename that folder first, or create the repository with
--no-scaffold. The checkout a scaffold makes never holds your git token, and a scaffold that fails
removes the checkout it made.
Where Create repository failed to push before 0.24.0, the checkout it left in the instance's add-ons
may still hold your git token in .git/config. Delete that checkout, or revoke the token at your
git provider and issue a new one.
Several profiles on one machine
$ ohm dev switch acme-live --openOne profile runs at a time: switching makes this one the running profile and stops the others. They share the workstation's PostgreSQL, so what a stopped profile costs you is disk, not memory.
Publishing back
$ ohm dev publish acme-live --dry-run$ ohm dev publish acme-live --module sale_custom --installPublishing sends the module pins back to the customer instance - not your code, and not the database. The code reaches the customer the way it always does, by being pushed to the repository the customer's instance pulls from. What publishing changes is which commit that instance is pinned to.
--dry-run reports what would be published and calls nothing. With no --module, every changed
module goes. --install queues a module install on the customer instance afterwards.
Expiry
A profile expires 30 days after it was created unless you said otherwise, and a daily maintenance job purges the ones that are due.
That job is housekeeping, so it runs at every edition including Unregistered. A lapsed license must not be a reason customer data stays alive on a laptop.
A purge deletes the profile row, removes the local instance and its data, and removes the instance's image. It does not archive anything - see what a workstation does differently.
A profile with uncommitted or unpushed work is not purged on the day. It is reported instead - on the page, and by mail when a notification profile exists - and purged seven days later regardless. Treat that week as the warning it is.
$ ohm dev remove acme-live --keep-instance--keep-instance deletes the profile row only, leaving the local instance and its data in place.
Without it, both go.