diff --git a/github_app_geo_project/module/__init__.py b/github_app_geo_project/module/__init__.py index 2b8267abb7..47f6e0ecf4 100644 --- a/github_app_geo_project/module/__init__.py +++ b/github_app_geo_project/module/__init__.py @@ -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) -> list[str] | None: + """ + 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..3dae2ec4d0 100644 --- a/github_app_geo_project/module/standard/changelog.py +++ b/github_app_geo_project/module/standard/changelog.py @@ -484,6 +484,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) -> list[str] | None: + """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 +497,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 +521,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 +570,7 @@ async def process( ) assert isinstance(repository, str) - tag_str = "" + tag_str = cast(str, context.module_event_data.get("version")) milestone = None release = None if context.module_event_data.get("type") == "tag": @@ -547,7 +578,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 +593,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..427905a7e4 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,15 +230,52 @@ def process_event(context: ProcessContext) -> None: github_application=context.github_application, ) ): + priority = action.priority if action.priority >= 0 else module.PRIORITY_STANDARD + event_name = action.title or context.event_name + module_data = current_module.event_data_to_json(action.data) + + 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 == 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 == module_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 - job.event_name = action.title or context.event_name + job.event_name = event_name job.event_data = context.event_data job.module = name - job.module_data = current_module.event_data_to_json(action.data) + job.module_data = module_data context.session.add(job) context.session.flush()