Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d019540
[DOC] plan the ticket release feature
sebastienbeau Oct 31, 2026
ac3f1be
[ADD] support_release, support_server_release
sebastienbeau Oct 31, 2026
a55cc7b
[IMP] support_server_release: notify a release in production
sebastienbeau Oct 31, 2026
aa74df0
[IMP] support_release, support_server_release: apply the review
sebastienbeau Oct 31, 2026
2cbeb7e
[IMP] support_release, support_server_release: apply the second review
sebastienbeau Nov 2, 2026
a0a3805
[IMP] support_release: use the Akretion icon
sebastienbeau Nov 2, 2026
8409d54
[IMP] support_release, support_server_release: apply the third review
sebastienbeau Nov 2, 2026
46d0b61
[IMP] support_server_release: send the production mail in the custome…
sebastienbeau Nov 2, 2026
5168437
[IMP] support_server_release: move the release stages in the project …
sebastienbeau Nov 3, 2026
7123433
[IMP] support_server_release: group the tickets by project in the mail
sebastienbeau Nov 3, 2026
0c530a7
[IMP] support_server_release: keep the internal tickets out of the mail
sebastienbeau Nov 3, 2026
d227891
[IMP] support_server_release: show the releases on the project tasks
sebastienbeau Nov 3, 2026
2f3684a
[IMP] support_server_release: open the tickets from the release
sebastienbeau Nov 3, 2026
3da5247
[IMP] support_server_release: give the customer access to its releases
sebastienbeau Nov 3, 2026
1efe3d6
[IMP] support_server_release: drop the useless rule on the customer a…
sebastienbeau Nov 3, 2026
296f4ec
[IMP] support_server_release: open the right views from a release
sebastienbeau Nov 3, 2026
1d85273
[IMP] support_server_release: reuse the task action of the user
sebastienbeau Nov 3, 2026
818a913
[IMP] support_server_release: keep the name of the task action
sebastienbeau Nov 3, 2026
0dbe4ab
[IMP] support_server_release: open the tickets as a plain list
sebastienbeau Nov 3, 2026
b8df494
[IMP] support_server_release: keep the favourites out of the release …
sebastienbeau Nov 3, 2026
bfa0d52
[IMP] support_server_release: open the tickets without the grouping b…
sebastienbeau Nov 3, 2026
5c8e097
support_server_release: remove useless field in view
sebastienbeau Nov 3, 2026
ee88811
[IMP] support_server_release: link the tickets with the action of the…
sebastienbeau Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
595 changes: 595 additions & 0 deletions PLAN-support-release.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions setup/_metapackage/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ dependencies = [
"odoo-addon-project_customer_access==18.0.*",
"odoo-addon-support==18.0.*",
"odoo-addon-support_akretion==18.0.*",
"odoo-addon-support_release==18.0.*",
"odoo-addon-support_server==18.0.*",
"odoo-addon-support_server_release==18.0.*",
]
classifiers=[
"Programming Language :: Python",
Expand Down
114 changes: 114 additions & 0 deletions support_release/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
===============
Support Release
===============

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0c56dd86e3e17aa7d60d7bcaab1a85dddfe02ff793f56e69da581d851840fa2a
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-Akretion%2Fsupport-lightgray.png?logo=github
:target: https://github.com/Akretion/support/tree/18.0/support_release
:alt: Akretion/support

|badge1| |badge2| |badge3|

This module records the releases deployed on a customer project and
pushes them to the Akretion support server, where the tickets shipped by
each release are linked and moved to the stage matching the deployment
environment.

The information comes from a migration generated in the project by the
release script, so the module never reads git: it only stores what the
migration hands it and relays it.

A release is identified by its version. When no version is defined yet,
the version is ``next``, and the first numbered version absorbs it.

**Table of contents**

.. contents::
:local:

Usage
=====

The release information is registered by a migration generated in the
project (usually ``custom_all``) at each deployment:

.. code:: python

from openupgradelib import openupgrade


@openupgrade.migrate(use_env=True)
def migrate(env, version):
if "support.release" not in env:
return
env["support.release"]._register_deployment(
version="next", # or the numbered version, e.g. "14.0.2610.26.0"
tickets=[25882, 25890],
)

The guard on the model presence keeps a database where this module is
not installed from failing its module update.

Releases are then pushed by the cron *Support Release: push pending
releases* (every 10 minutes, one release per run, in the default order
of the model, so the most recently registered pending one first).

Every deployment sends the complete list of tickets of the release, so
registering the same version again replaces its tickets instead of
completing them. A call with a version or a ticket list that cannot be
used raises: a broken generated migration must be visible in the log,
not silently ignored.

A release is only marked as sent once the support server accepted it, so
a failed push is retried by the next run.

The push only happens when ``running_env`` is ``preprod`` or ``prod``:
it is set by ``server_environment`` from the ``RUNNING_ENV`` environment
variable, so there is nothing else to configure in the module.

The generated migration must exist on the **main branch only**: the CI
sets ``RUNNING_ENV=preprod`` on every container, so a review environment
carrying a migration would announce a version that was never deployed.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/Akretion/support/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/Akretion/support/issues/new?body=module:%20support_release%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Akretion

Contributors
------------

- Sébastien Beau <sebastien.beau@akretion.com>

Maintainers
-----------

This module is part of the `Akretion/support <https://github.com/Akretion/support/tree/18.0/support_release>`_ project on GitHub.

You are welcome to contribute.
4 changes: 4 additions & 0 deletions support_release/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 Akretion (http://www.akretion.com).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
20 changes: 20 additions & 0 deletions support_release/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2026 Akretion (http://www.akretion.com).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Support Release",
"summary": "Record the releases of a project and push them to the support server",
"version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "Akretion",
"website": "https://github.com/akretion/support",
"depends": [
"support",
],
"data": [
"security/ir.model.access.csv",
"data/ir_cron.xml",
"views/support_release_views.xml",
],
"installable": True,
}
14 changes: 14 additions & 0 deletions support_release/data/ir_cron.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2026 Akretion (http://www.akretion.com).
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo noupdate="1">
<record id="ir_cron_push_releases" model="ir.cron">
<field name="name">Support Release: push pending releases</field>
<field name="model_id" ref="model_support_release" />
<field name="state">code</field>
<field name="code">model._cron_push_releases()</field>
<field name="interval_number">10</field>
<field name="interval_type">minutes</field>
<field name="active" eval="True" />
</record>
</odoo>
4 changes: 4 additions & 0 deletions support_release/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 Akretion (http://www.akretion.com).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import support_release
92 changes: 92 additions & 0 deletions support_release/models/support_release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright 2026 Akretion (http://www.akretion.com).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import _, api, fields, models, tools
from odoo.exceptions import UserError

NEXT_VERSION = "next"
SUPPORTED_ENVIRONMENTS = ("preprod", "prod")


class SupportRelease(models.Model):
_name = "support.release"
_description = "Support Release"
_rec_name = "version"
_order = "id desc"

version = fields.Char(
required=True,
index=True,
help="Version of the deployment, or 'next' while no version is defined.",
)
tickets = fields.Json(
help="Ids of the tickets shipped by this release.",
)
is_sent = fields.Boolean(
default=False,
copy=False,
help="Set once the support server has accepted the release.",
)

_sql_constraints = [
(
"version_uniq",
"unique(version)",
"A release already exists for this version.",
),
]

@api.model
def _get_environment(self):
"""Return the deployment environment, or False when releases stay silent."""
running_env = tools.config.get("running_env")
return running_env if running_env in SUPPORTED_ENVIRONMENTS else False

@api.model
def _register_deployment(self, version, tickets):
"""Record a deployment, called from the migration of the project.

Each deployment sends every ticket of the release, so the last payload
replaces the previous one instead of completing it.
"""
version = (version or "").strip()
if version.lower() == NEXT_VERSION:
version = NEXT_VERSION
if not version:
raise ValueError("a release needs a version")
if not isinstance(tickets, list | tuple) or not all(
isinstance(ticket, int) for ticket in tickets
):
raise ValueError("tickets must be a list of ticket ids")
release = self.search([("version", "=", version)]) or self.create(
{"version": version}
)
release.tickets = list(tickets)
if version != NEXT_VERSION:
self.search([("version", "=", NEXT_VERSION)]).unlink()
return release

def _build_payload(self):
self.ensure_one()
return {
"environment": self._get_environment(),
"version": self.version,
"tickets": self.tickets or [],
}

def _push(self):
self.ensure_one()
server = self.env.ref("support.support_server", raise_if_not_found=False)
if not server:
raise UserError(_("The support server is not configured."))
server.sudo()._request("POST", "/release", data=self._build_payload())
self.is_sent = True

@api.model
def _cron_push_releases(self):
"""Push one pending release per cron run, in the default model order."""
if not self._get_environment():
return
release = self.search([("is_sent", "=", False)], limit=1)
if release:
release._push()
3 changes: 3 additions & 0 deletions support_release/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
1 change: 1 addition & 0 deletions support_release/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Sébastien Beau \<<sebastien.beau@akretion.com>\>
10 changes: 10 additions & 0 deletions support_release/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This module records the releases deployed on a customer project and pushes them
to the Akretion support server, where the tickets shipped by each release are
linked and moved to the stage matching the deployment environment.

The information comes from a migration generated in the project by the release
script, so the module never reads git: it only stores what the migration hands
it and relays it.

A release is identified by its version. When no version is defined yet, the
version is `next`, and the first numbered version absorbs it.
39 changes: 39 additions & 0 deletions support_release/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
The release information is registered by a migration generated in the project
(usually `custom_all`) at each deployment:

```python
from openupgradelib import openupgrade


@openupgrade.migrate(use_env=True)
def migrate(env, version):
if "support.release" not in env:
return
env["support.release"]._register_deployment(
version="next", # or the numbered version, e.g. "14.0.2610.26.0"
tickets=[25882, 25890],
)
```

The guard on the model presence keeps a database where this module is not
installed from failing its module update.

Releases are then pushed by the cron *Support Release: push pending releases*
(every 10 minutes, one release per run, in the default order of the model, so
the most recently registered pending one first).

Every deployment sends the complete list of tickets of the release, so
registering the same version again replaces its tickets instead of completing
them. A call with a version or a ticket list that cannot be used raises: a
broken generated migration must be visible in the log, not silently ignored.

A release is only marked as sent once the support server accepted it, so a
failed push is retried by the next run.

The push only happens when `running_env` is `preprod` or `prod`: it is set by
`server_environment` from the `RUNNING_ENV` environment variable, so there is
nothing else to configure in the module.

The generated migration must exist on the **main branch only**: the CI sets
`RUNNING_ENV=preprod` on every container, so a review environment carrying a
migration would announce a version that was never deployed.
2 changes: 2 additions & 0 deletions support_release/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_support_release_system,support.release system,model_support_release,base.group_system,1,1,0,0
Binary file added support_release/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading