Skip to content

Commit 20bca90

Browse files
committed
Add queued label to PR for events in queue
A webhook dispatcher sets a PR label once there is not enough capacity on a cluster and event gets in a queue. The queue label matches a current label pattern for each pipeline. The example for hosted pipeline is "operator-hosted-pipeline/queued". This format makes sure the label is removed once the pipeline starts processing the PR. The label is set only once when the event gets in a queue. The event corresponding DB entry is also changed to indicate queued status. JIRA: ISV-6265 Signed-off-by: Ales Raszka <[email protected]>
1 parent 1d7612a commit 20bca90

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

ansible/roles/operator-pipeline/templates/openshift/webhook_dispatcher/webhook-dispatcher-deployment.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ spec:
6565
secretKeyRef:
6666
name: github-webhook-secret
6767
key: webhook-secret
68+
- name: GITHUB_TOKEN
69+
valueFrom:
70+
secretKeyRef:
71+
name: github-bot-token
72+
key: github_bot_token
6873
volumeMounts:
6974
- name: "webhook-dispatcher-config"
7075
mountPath: "/home/user/dispatcher-config.yml"

operator-pipeline-images/operatorcert/webhook_dispatcher/dispatcher.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55

66
import asyncio
77
import logging
8+
import os
89
from datetime import datetime
910
from typing import Any
1011

1112
import celpy
1213
import celpy.adapter
1314
import celpy.evaluation
15+
from github import Auth, Github
16+
from operatorcert.github import add_labels_to_pull_request
1417
from operatorcert.webhook_dispatcher.config import (
1518
DispatcherConfig,
1619
DispatcherConfigItem,
@@ -234,6 +237,11 @@ async def process_pipeline_event(self, pipeline_event: PipelineEvent) -> None:
234237
LOGGER.debug(
235238
"There is not enough capacity to process the event %s", event.id
236239
)
240+
if event.status != "queued":
241+
# Mark the event as queued and set the GitHub label
242+
self.set_github_queued_label(pipeline_event)
243+
event.status = "queued"
244+
237245
# Waiting for a next loop to process the event
238246
return
239247

@@ -315,3 +323,22 @@ def _group_by_repository_and_pull_request(
315323
output[event.repository_full_name][event.pull_request_number] = []
316324
output[event.repository_full_name][event.pull_request_number].append(event)
317325
return output
326+
327+
@staticmethod
328+
def set_github_queued_label(pipeline_event: PipelineEvent) -> None:
329+
"""
330+
Set the "github/queued" label on the pull request associated with the event.
331+
332+
Args:
333+
event (WebhookEvent): A WebhookEvent object for which to set the label.
334+
"""
335+
github_auth = Auth.Token(os.environ.get("GITHUB_TOKEN") or "")
336+
github = Github(auth=github_auth)
337+
338+
event = pipeline_event.event
339+
label = f"{pipeline_event.config_item.capacity.pipeline_name}/queued"
340+
341+
repo = github.get_repo(event.repository_full_name)
342+
pull_request = repo.get_pull(event.pull_request_number)
343+
add_labels_to_pull_request(pull_request, [label])
344+
LOGGER.info("Set label '%s' on pull request %s", label, pull_request.html_url)

operator-pipeline-images/tests/webhook_dispatcher/test_dispatcher.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,15 @@ def test_convert_to_pipeline_event(
297297

298298
@pytest.mark.asyncio
299299
@patch("operatorcert.webhook_dispatcher.dispatcher.asyncio.sleep")
300+
@patch(
301+
"operatorcert.webhook_dispatcher.dispatcher.EventDispatcher.set_github_queued_label"
302+
)
300303
@patch("operatorcert.webhook_dispatcher.dispatcher.PipelineEvent.trigger_pipeline")
301304
@patch("operatorcert.webhook_dispatcher.dispatcher.PipelineEvent.is_capacity_available")
302305
async def test_process_pipeline_event(
303306
mock_is_capacity_available: AsyncMock,
304307
mock_trigger_pipeline: AsyncMock,
308+
mock_set_github_queued_label: MagicMock,
305309
mock_time_sleep: MagicMock,
306310
dispatcher: EventDispatcher,
307311
) -> None:
@@ -319,14 +323,17 @@ async def test_process_pipeline_event(
319323
# no capacity
320324
await dispatcher.process_pipeline_event(pipeline_event)
321325
mock_trigger_pipeline.assert_not_called()
326+
mock_set_github_queued_label.assert_called_once_with(pipeline_event)
322327
assert pipeline_event.event.processed == False
323328

324329
# capacity available but trigger pipeline failed
325330
mock_trigger_pipeline.reset_mock()
331+
mock_set_github_queued_label.reset_mock()
326332
mock_trigger_pipeline.return_value = False
327333
mock_is_capacity_available.return_value = True
328334
await dispatcher.process_pipeline_event(pipeline_event)
329335
mock_trigger_pipeline.assert_called_once_with()
336+
mock_set_github_queued_label.assert_not_called()
330337
assert pipeline_event.event.processed == False
331338

332339
# capacity available and trigger pipeline successful
@@ -519,3 +526,49 @@ def test_match_cel_expression(
519526

520527
result = dispatcher.match_cel_expression(event, item.filter.cel_expression) # type: ignore
521528
assert result is expected_result
529+
530+
531+
@patch("operatorcert.webhook_dispatcher.dispatcher.add_labels_to_pull_request")
532+
@patch("operatorcert.webhook_dispatcher.dispatcher.Github")
533+
@patch("operatorcert.webhook_dispatcher.dispatcher.Auth")
534+
def test_set_github_queued_label(
535+
mock_auth: MagicMock,
536+
mock_github: MagicMock,
537+
mock_add_labels: MagicMock,
538+
monkeypatch: Any,
539+
) -> None:
540+
monkeypatch.setenv("GITHUB_TOKEN", "test_token")
541+
config_item = DispatcherConfigItem(
542+
name="test1.0",
543+
events=["pull_request"],
544+
full_repository_name="test/test",
545+
callback_url="http://test.com",
546+
capacity=CapacityConfig(
547+
type="test",
548+
pipeline_name="my-pipeline",
549+
max_capacity=10,
550+
namespace="test",
551+
),
552+
)
553+
event = WebhookEvent(
554+
id=1,
555+
repository_full_name="test/test",
556+
pull_request_number=1,
557+
action="push",
558+
processed=False,
559+
processing_error=None,
560+
)
561+
pipeline_event = PipelineEvent(event, config_item)
562+
mock_pull_request = MagicMock()
563+
mock_github.return_value.get_repo.return_value.get_pull.return_value = (
564+
mock_pull_request
565+
)
566+
EventDispatcher.set_github_queued_label(pipeline_event)
567+
568+
mock_auth.Token.assert_called_once_with("test_token")
569+
mock_github.assert_called_once_with(auth=mock_auth.Token.return_value)
570+
571+
mock_github.return_value.get_repo.assert_called_once_with("test/test")
572+
mock_github.return_value.get_repo.return_value.get_pull.assert_called_once_with(1)
573+
574+
mock_add_labels.assert_called_once_with(mock_pull_request, ["my-pipeline/queued"])

0 commit comments

Comments
 (0)