diff --git a/github_app_geo_project/module/__init__.py b/github_app_geo_project/module/__init__.py index 2b8267abb7..157b8c0ad0 100644 --- a/github_app_geo_project/module/__init__.py +++ b/github_app_geo_project/module/__init__.py @@ -4,7 +4,7 @@ import logging from abc import abstractmethod from types import GenericAlias -from typing import Any, Generic, Literal, NamedTuple, NotRequired, TypedDict, TypeVar +from typing import Any, Generic, Literal, NamedTuple, NotRequired, Optional, TypedDict, TypeVar from pydantic import BaseModel, ValidationError from sqlalchemy.orm import Session @@ -321,6 +321,14 @@ def documentation_url(self) -> str: """Get the URL to the documentation page of the module.""" return "" + def jobs_unique_on(self) -> Optional(list[str]): + """ + Return the list of fields that should be unique for the jobs. + + If not unique, the other jobs will be skipped. + """ + return None + @abstractmethod def get_actions(self, context: GetActionContext) -> list[Action[_EVENT_DATA]]: """ diff --git a/github_app_geo_project/module/standard/changelog.py b/github_app_geo_project/module/standard/changelog.py index f957b4ad83..e659f6d5b1 100644 --- a/github_app_geo_project/module/standard/changelog.py +++ b/github_app_geo_project/module/standard/changelog.py @@ -9,6 +9,7 @@ import github import packaging.version +from git import Optional from github_app_geo_project import module from github_app_geo_project.module import utils @@ -484,6 +485,10 @@ def documentation_url(self) -> str: """Get the URL to the documentation page of the module.""" return "https://github.com/camptocamp/github-app-geo-project/wiki/Module-%E2%80%90-Changelog" + def jobs_unique_on(self) -> Optional(list[str]): + """Indicate fields used to ship other jobs.""" + return ["repository", "owner", "module_data"] + def get_actions(self, context: module.GetActionContext) -> list[module.Action[dict[str, Any]]]: """ Get the action related to the module and the event. @@ -493,9 +498,18 @@ def get_actions(self, context: module.GetActionContext) -> list[module.Action[di """ event_data = context.event_data if "release" in event_data and event_data.get("action") == "created": - return [module.Action(priority=module.PRIORITY_STATUS, data={"type": "release"})] + return [ + module.Action( + priority=module.PRIORITY_STATUS, + data={"type": "release", "version": event_data["release"]["tag_name"]}, + ) + ] if event_data.get("ref_type") == "tag": - return [module.Action(priority=module.PRIORITY_STATUS, data={"type": "tag"})] + return [ + module.Action( + priority=module.PRIORITY_STATUS, data={"type": "tag", "version": event_data["ref"]} + ) + ] if ( ( event_data.get("action") == "edited" @@ -508,11 +522,29 @@ def get_actions(self, context: module.GetActionContext) -> list[module.Action[di and event_data.get("sender", {}).get("login") != context.github_application.integration.get_app().slug + "[bot]" ): - return [module.Action(priority=module.PRIORITY_CRON, data={"type": "pull_request"})] + return [ + module.Action( + priority=module.PRIORITY_CRON, + data={ + "type": "pull_request", + "version": event_data["pull_request"]["milestone"]["title"], + }, + ) + ] if event_data.get("action") == "edited" and "milestone" in event_data: - return [module.Action(priority=module.PRIORITY_CRON, data={"type": "milestone"})] + return [ + module.Action( + priority=module.PRIORITY_CRON, + data={"type": "milestone", "version": event_data["milestone"]["title"]}, + ) + ] if event_data.get("action") in ("created", "closed") and "discussion" in event_data: - return [module.Action(priority=module.PRIORITY_CRON, data={"type": "discussion"})] + return [ + module.Action( + priority=module.PRIORITY_CRON, + data={"type": "discussion", "title": event_data["discussion"]["title"]}, + ) + ] return [] @@ -539,7 +571,7 @@ async def process( ) assert isinstance(repository, str) - tag_str = "" + tag_str = context.module_event_data.get("version") milestone = None release = None if context.module_event_data.get("type") == "tag": @@ -547,7 +579,7 @@ async def process( "create-release", changelog_configuration.CREATE_RELEASE_DEFAULT ): return module.ProcessOutput() - tag_str = cast(str, context.event_data["ref"]) + prerelease = False try: latest_release = repo.get_latest_release() @@ -562,10 +594,8 @@ async def process( elif context.module_event_data.get("type") == "release": if context.module_config.get("create-release", changelog_configuration.CREATE_RELEASE_DEFAULT): return module.ProcessOutput() - tag_str = context.event_data.get("release", {}).get("tag_name") release = repo.get_release(tag_str) elif context.module_event_data.get("type") == "milestone": - tag_str = context.event_data.get("milestone", {}).get("title") tags = [tag for tag in repo.get_tags() if tag.name == tag_str] if not tags: _LOGGER.info( diff --git a/github_app_geo_project/views/webhook.py b/github_app_geo_project/views/webhook.py index 5e7e5f8daf..cd354a86f8 100644 --- a/github_app_geo_project/views/webhook.py +++ b/github_app_geo_project/views/webhook.py @@ -11,6 +11,7 @@ import pyramid.request import sqlalchemy.engine import sqlalchemy.orm +from numpy import where from pyramid.view import view_config from sqlalchemy.orm import Session @@ -229,8 +230,46 @@ def process_event(context: ProcessContext) -> None: github_application=context.github_application, ) ): + priority = action.priority if action.priority >= 0 else module.PRIORITY_STANDARD + jobs_unique_on = current_module.jobs_unique_on() + if jobs_unique_on: + + update = ( + sqlalchemy.update(models.Queue) + .where(models.Queue.status == models.JobStatus.NEW) + .where(models.Queue.application == context.application) + .where(models.Queue.module == name) + ) + for key in jobs_unique_on: + if key == "priority": + update = update.where(models.Queue.priority == priority) + elif key == "owner": + update = update.where(models.Queue.owner == context.owner) + elif key == "repository": + update = update.where(models.Queue.repository == context.repository) + elif key == "event_name": + update = update.where( + models.Queue.event_name == action.title or context.event_name + ) + elif key == "event_data": + update = update.where(models.Queue.event_data == context.event_data) + elif key == "module_data": + update = update.where( + models.Queue.module_data == current_module.event_data_to_json(action.data) + ) + else: + _LOGGER.error("Unknown jobs_unique_on key: %s", key) + + update = update.values( + { + "status": models.JobStatus.SKIPPED, + } + ) + + context.session.execute(update) + job = models.Queue() - job.priority = action.priority if action.priority >= 0 else module.PRIORITY_STANDARD + job.priority = priority job.application = context.application job.owner = context.owner job.repository = context.repository