Skip to content
Merged
3 changes: 3 additions & 0 deletions environment.sample
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ ODOO_PASSWORD=
# Number of days before the proposal can be marked as "Approved"
#MIN_PR_AGE=5

# Color of the github label that contains the name of the module
#MODULE_LABEL_COLOR=#ffc

# Coma separated list of task to run
# By default all configured tasks are run.
# Available tasks:
Expand Down
4 changes: 3 additions & 1 deletion src/oca_github_bot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def func_wrapper(*args, **kwargs):
# Available tasks:
# delete_branch,tag_approved,tag_ready_to_merge,gen_addons_table,
# gen_addons_readme,gen_addons_icon,setuptools_odoo,merge_bot,tag_needs_review,
# migration_issue_bot,whool_init,gen_metapackage
# migration_issue_bot,whool_init,gen_metapackage,label_modified_addons
BOT_TASKS = os.environ.get("BOT_TASKS", "all").split(",")

BOT_TASKS_DISABLED = os.environ.get("BOT_TASKS_DISABLED", "").split(",")
Expand Down Expand Up @@ -101,6 +101,8 @@ def func_wrapper(*args, **kwargs):
APPROVALS_REQUIRED = int(os.environ.get("APPROVALS_REQUIRED", "2"))
MIN_PR_AGE = int(os.environ.get("MIN_PR_AGE", "5"))

MODULE_LABEL_COLOR = os.environ.get("MODULE_LABEL_COLOR", "#ffc")

dist_publisher = MultiDistPublisher()
SIMPLE_INDEX_ROOT = os.environ.get("SIMPLE_INDEX_ROOT")
if SIMPLE_INDEX_ROOT:
Expand Down
1 change: 1 addition & 0 deletions src/oca_github_bot/tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from . import (
heartbeat,
label_modified_addons,
main_branch_bot,
mention_maintainer,
migration_issue_bot,
Expand Down
62 changes: 62 additions & 0 deletions src/oca_github_bot/tasks/label_modified_addons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright (c) ACSONE SA/NV 2024
# Distributed under the MIT License (http://opensource.org/licenses/MIT).

from .. import github
from ..config import MODULE_LABEL_COLOR, switchable
from ..manifest import git_modified_addons
from ..process import check_call
from ..queue import task
from ..utils import compute_module_label_name
from ..version_branch import is_main_branch_bot_branch


def _label_modified_addons(gh, org, repo, pr, dry_run):
gh_repo = gh.repository(org, repo)
gh_pr = gh.pull_request(org, repo, pr)
target_branch = gh_pr.base.ref
pr_branch = f"tmp-pr-{pr}"
with github.temporary_clone(org, repo, target_branch) as clone_dir:
check_call(
["git", "fetch", "origin", f"pull/{pr}/head:{pr_branch}"],
cwd=clone_dir,
)
check_call(["git", "checkout", pr_branch], cwd=clone_dir)
modified_addons, _ = git_modified_addons(clone_dir, target_branch)
if not modified_addons:
return
gh_issue = github.gh_call(gh_pr.issue)
repo_label_names = [label.name for label in gh_repo.labels()]
issue_label_names = [label.name for label in gh_issue.labels()]

new_labels = set()
for modified_addon in modified_addons:
label_name = compute_module_label_name(modified_addon)
# We create label at repo level, because it is possible to
# to set description in create_label() function
# (and not in issue.add_labels())
if label_name not in repo_label_names and not dry_run:
github.gh_call(
gh_repo.create_label,
name=label_name,
description=f"Module {modified_addon}",
color=MODULE_LABEL_COLOR.replace("#", ""),
)
new_labels.add(label_name)

if is_main_branch_bot_branch(target_branch):
new_labels.add(f"series:{target_branch}")
new_labels |= {
x
for x in issue_label_names
if not (x.startswith("mod:") or x.startswith("series:"))
}

if not dry_run and new_labels != set(issue_label_names):
github.gh_call(gh_issue.replace_labels, list(new_labels))


@task()
@switchable("label_modified_addons")
def label_modified_addons(org, repo, pr, dry_run=False):
with github.login() as gh:
_label_modified_addons(gh, org, repo, pr, dry_run)
28 changes: 28 additions & 0 deletions src/oca_github_bot/utils.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# Copyright (c) ACSONE SA/NV 2021
# Distributed under the MIT License (http://opensource.org/licenses/MIT).

import hashlib
import re
import shlex
import time
from typing import Sequence

from . import config

# Max size allowed by github for label name
_MAX_LABEL_SIZE = 50
# Size of the hash, added at the end of the label name
# if module name is too long
_HASH_SIZE = 5


def hide_secrets(s: str) -> str:
# TODO do we want to hide other secrets ?
Expand All @@ -33,3 +40,24 @@ def retry_on_exception(

def cmd_to_str(cmd: Sequence[str]) -> str:
return shlex.join(str(c) for c in cmd)


def compute_module_label_name(module_name: str) -> str:
"""To avoid error if label name is too long
we cut big label, and finish by a hash of the module name.
(The full module name will be present in the description).
Short module name exemple :
- module : 'web_responsive'
- label : 'mod:web_responsive'
Long module name exemple :
- module : 'account_invoice_supplierinfo_update_triple_discount'
- label : 'mod:account_invoice_supplierinfo_update_trip bf3f3'
"""
label_name = f"mod:{module_name}"
if len(label_name) > _MAX_LABEL_SIZE:
module_hash = hashlib.sha256(bytes(module_name, "utf-8")).hexdigest()
label_name = (
f"{label_name[:(_MAX_LABEL_SIZE - (_HASH_SIZE + 1))]}"
f" {module_hash[:_HASH_SIZE]}"
)
return label_name
2 changes: 1 addition & 1 deletion src/oca_github_bot/version_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def is_main_branch_bot_branch(branch_name):


def is_protected_branch(branch_name):
if branch_name == "master":
if branch_name in ("master", "main"):
return True
return bool(ODOO_VERSION_RE.match(branch_name))

Expand Down
1 change: 1 addition & 0 deletions src/oca_github_bot/webhooks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
on_command,
on_pr_close_delete_branch,
on_pr_green_label_needs_review,
on_pr_label_modified_addons,
on_pr_open_label_new_contributor,
on_pr_open_mention_maintainer,
on_pr_review,
Expand Down
21 changes: 21 additions & 0 deletions src/oca_github_bot/webhooks/on_pr_label_modified_addons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) ACSONE SA/NV 2024
# Distributed under the MIT License (http://opensource.org/licenses/MIT).

import logging

from ..router import router
from ..tasks.label_modified_addons import label_modified_addons

_logger = logging.getLogger(__name__)


@router.register("pull_request", action="opened")
@router.register("pull_request", action="reopened")
@router.register("pull_request", action="synchronize")
async def on_pr_label_modified_addons(event, *args, **kwargs):
"""
Whenever a PR is opened, add labels based on modified addons.
"""
org, repo = event.data["repository"]["full_name"].split("/")
pr = event.data["pull_request"]["number"]
label_modified_addons.delay(org, repo, pr)
Loading
Loading