Skip to content

Commit 4dc4920

Browse files
authored
Revert "Reapply "feat(review): Automatically call for review when a PR become…" (#45186)
Reverts #45126
1 parent 0e4655e commit 4dc4920

File tree

5 files changed

+67
-190
lines changed

5 files changed

+67
-190
lines changed

.github/workflows/ask_review.yml

Lines changed: 0 additions & 28 deletions
This file was deleted.

.github/workflows/label-analysis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,21 @@ jobs:
126126
features: legacy-tasks
127127
- name: Check agent telemetry metric list
128128
run: dda inv -- -e github.agenttelemetry-list-change-ack-check --pr-id=${{ github.event.pull_request.number }}
129+
130+
ask-reviews:
131+
if: github.triggering_actor != 'dd-devflow[bot]' && github.event.action == 'labeled' && github.event.label.name == 'ask-review'
132+
runs-on: ubuntu-latest
133+
steps:
134+
- name: Checkout repository
135+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
136+
with:
137+
persist-credentials: false
138+
- name: Install dda
139+
uses: ./.github/actions/install-dda
140+
with:
141+
features: legacy-tasks
142+
- name: Ask for code reviews
143+
env:
144+
SLACK_DATADOG_AGENT_BOT_TOKEN : ${{ secrets.SLACK_DATADOG_AGENT_BOT_TOKEN }}
145+
PR_REQUESTED_TEAMS: ${{ toJSON(github.event.pull_request.requested_teams) }}
146+
run: dda inv -- -e issue.ask-reviews -p ${{ github.event.pull_request.number }}

tasks/issue.py

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from invoke.tasks import task
88

9-
from tasks.libs.ciproviders.github_api import GithubAPI, get_events_info
9+
from tasks.libs.ciproviders.github_api import GithubAPI, ask_review_actor
1010
from tasks.libs.owners.parsing import search_owners
1111
from tasks.libs.pipeline.notifications import (
1212
DEFAULT_SLACK_CHANNEL,
@@ -21,44 +21,39 @@ def ask_reviews(_, pr_id):
2121
if 'backport' in pr.title.casefold():
2222
print("This is a backport PR, we don't need to ask for reviews.")
2323
return
24-
if any(label.name == 'no-review' for label in pr.get_labels()):
25-
print("This PR has the no-review label, we don't need to ask for reviews.")
26-
return
27-
actor, team = get_events_info(pr)
28-
if team: # This is a review request event, only a single team is concerned
29-
reviewers = [f"@datadog/{team}"]
30-
else:
24+
if any(label.name == 'ask-review' for label in pr.get_labels()):
25+
actor = ask_review_actor(pr)
3126
reviewers = [f"@datadog/{team['slug']}" for team in json.loads(os.environ['PR_REQUESTED_TEAMS'])]
32-
print(f"Reviewers: {reviewers}")
33-
34-
from slack_sdk import WebClient
35-
36-
client = WebClient(os.environ['SLACK_DATADOG_AGENT_BOT_TOKEN'])
37-
emojis = client.emoji_list()
38-
waves = [emoji for emoji in emojis.data['emoji'] if 'wave' in emoji and 'microwave' not in emoji]
39-
40-
channels = defaultdict(list)
41-
for reviewer in reviewers:
42-
channel = next(
43-
(chan for team, chan in GITHUB_SLACK_REVIEW_MAP.items() if team.casefold() == reviewer.casefold()),
44-
DEFAULT_SLACK_CHANNEL,
45-
)
46-
channels[channel].append(reviewer)
47-
48-
for channel, reviewers in channels.items():
49-
stop_updating = ""
50-
if (pr.user.login == "renovate[bot]" or pr.user.login == "mend[bot]") and pr.title.startswith(
51-
"chore(deps): update integrations-core"
52-
):
53-
stop_updating = "Add the `stop-updating` label before trying to merge this PR, to prevent it from being updated by Renovate.\n"
54-
message = f'Hello :{random.choice(waves)}:!\n*{actor}* is asking review for PR <{pr.html_url}/s|{pr.title}>.\nCould you please have a look?\n{stop_updating}Thanks in advance!\n'
55-
if channel == DEFAULT_SLACK_CHANNEL:
56-
message = f'Hello :{random.choice(waves)}:!\nA review channel is missing for {', '.join(reviewers)}, can you please ask them to update `github_slack_review_map.yaml` and transfer them this review <{pr.html_url}/s|{pr.title}>?\n Thanks in advance!'
57-
try:
58-
client.chat_postMessage(channel=channel, text=message)
59-
except Exception as e:
60-
message = f"An error occurred while sending a review message from {actor} for PR <{pr.html_url}/s|{pr.title}> to channel {channel}. Error: {e}"
61-
client.chat_postMessage(channel=DEFAULT_SLACK_CHANNEL, text=message)
27+
print(f"Reviewers: {reviewers}")
28+
29+
from slack_sdk import WebClient
30+
31+
client = WebClient(os.environ['SLACK_DATADOG_AGENT_BOT_TOKEN'])
32+
emojis = client.emoji_list()
33+
waves = [emoji for emoji in emojis.data['emoji'] if 'wave' in emoji and 'microwave' not in emoji]
34+
35+
channels = defaultdict(list)
36+
for reviewer in reviewers:
37+
channel = next(
38+
(chan for team, chan in GITHUB_SLACK_REVIEW_MAP.items() if team.casefold() == reviewer.casefold()),
39+
DEFAULT_SLACK_CHANNEL,
40+
)
41+
channels[channel].append(reviewer)
42+
43+
for channel, reviewers in channels.items():
44+
stop_updating = ""
45+
if (pr.user.login == "renovate[bot]" or pr.user.login == "mend[bot]") and pr.title.startswith(
46+
"chore(deps): update integrations-core"
47+
):
48+
stop_updating = "Add the `stop-updating` label before trying to merge this PR, to prevent it from being updated by Renovate.\n"
49+
message = f'Hello :{random.choice(waves)}:!\n*{actor}* is asking review for PR <{pr.html_url}/s|{pr.title}>.\nCould you please have a look?\n{stop_updating}Thanks in advance!\n'
50+
if channel == DEFAULT_SLACK_CHANNEL:
51+
message = f'Hello :{random.choice(waves)}:!\nA review channel is missing for {', '.join(reviewers)}, can you please ask them to update `github_slack_review_map.yaml` and transfer them this review <{pr.html_url}/s|{pr.title}>?\n Thanks in advance!'
52+
try:
53+
client.chat_postMessage(channel=channel, text=message)
54+
except Exception as e:
55+
message = f"An error occurred while sending a review message from {actor} for PR <{pr.html_url}/s|{pr.title}> to channel {channel}. Error: {e}"
56+
client.chat_postMessage(channel=DEFAULT_SLACK_CHANNEL, text=message)
6257

6358

6459
@task

tasks/libs/ciproviders/github_api.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -754,18 +754,10 @@ def create_release_pr(title, base_branch, target_branch, version, changelog_pr=F
754754
return create_datadog_agent_pr(title, base_branch, target_branch, milestone_name, labels)
755755

756756

757-
def get_events_info(pr):
758-
actor, team = None, None
759-
for event in reversed(list(pr.get_issue_events())):
760-
if (event.event == "labeled" and event.label.name == "ask-review") or event.event in [
761-
"review_requested",
762-
"ready_for_review",
763-
]:
764-
actor = event.actor.name or event.actor.login
765-
if "requested_team" in event.raw_data:
766-
team = event.raw_data["requested_team"]["slug"]
767-
break
768-
return actor, team
757+
def ask_review_actor(pr):
758+
for event in pr.get_issue_events():
759+
if event.event == "labeled" and event.label.name == "ask-review":
760+
return event.actor.name or event.actor.login
769761

770762

771763
def generate_local_github_token(ctx):

tasks/unit_tests/issue_tests.py

Lines changed: 12 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ class TestAskReviews(unittest.TestCase):
143143
'os.environ',
144144
{'PR_REQUESTED_TEAMS': '[{"slug": "team1"}, {"slug": "team2"}]', 'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token'},
145145
)
146-
@patch('tasks.issue.get_events_info')
146+
@patch('tasks.issue.ask_review_actor')
147147
@patch('tasks.issue.GithubAPI')
148148
@patch('slack_sdk.WebClient')
149-
def test_ask_reviews_nominal(self, slack_mock, gh_mock, get_events_info_mock, print_mock):
149+
def test_ask_reviews_nominal(self, slack_mock, gh_mock, ask_review_actor_mock, print_mock):
150150
pr_mock = MagicMock()
151151
pr_mock.title = "This is a feature"
152152
pr_mock.get_labels.return_value = [types.SimpleNamespace(name='ask-review')]
@@ -157,7 +157,7 @@ def test_ask_reviews_nominal(self, slack_mock, gh_mock, get_events_info_mock, pr
157157
gh_instance = MagicMock()
158158
gh_instance.repo.get_pull.return_value = pr_mock
159159
gh_mock.return_value = gh_instance
160-
get_events_info_mock.return_value = ("actor", None)
160+
ask_review_actor_mock.return_value = "actor"
161161

162162
emoji_list = {'emoji': {'wave': 'url1', 'waves': 'url2', 'microwave': 'urlx'}}
163163
slack_client = MagicMock()
@@ -179,17 +179,17 @@ def test_ask_reviews_nominal(self, slack_mock, gh_mock, get_events_info_mock, pr
179179
'os.environ',
180180
{'PR_REQUESTED_TEAMS': '[{"slug": "team1"}, {"slug": "team2"}]', 'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token'},
181181
)
182-
@patch('tasks.issue.get_events_info')
182+
@patch('tasks.issue.ask_review_actor')
183183
@patch('tasks.issue.GithubAPI')
184-
def test_ask_reviews_backport(self, gh_mock, get_events_info_mock, print_mock):
184+
def test_ask_reviews_backport(self, gh_mock, ask_review_actor_mock, print_mock):
185185
pr_mock = MagicMock()
186186
pr_mock.title = "Backport: fix issue 123"
187187
pr_mock.get_labels.return_value = [MagicMock(name='ask-review')]
188188
gh_instance = MagicMock()
189189
gh_instance.repo.get_pull.return_value = pr_mock
190190
gh_mock.return_value = gh_instance
191191

192-
get_events_info_mock.return_value = ("actor", None)
192+
ask_review_actor_mock.return_value = "actor"
193193

194194
ask_reviews(MockContext(), 6)
195195
print_mock.assert_any_call("This is a backport PR, we don't need to ask for reviews.")
@@ -202,10 +202,10 @@ def test_ask_reviews_backport(self, gh_mock, get_events_info_mock, print_mock):
202202
'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token',
203203
},
204204
)
205-
@patch('tasks.issue.get_events_info')
205+
@patch('tasks.issue.ask_review_actor')
206206
@patch('tasks.issue.GithubAPI')
207207
@patch('slack_sdk.WebClient')
208-
def test_ask_reviews_default_channel(self, slack_mock, gh_mock, get_events_info_mock, print_mock):
208+
def test_ask_reviews_default_channel(self, slack_mock, gh_mock, ask_review_actor_mock, print_mock):
209209
pr_mock = MagicMock()
210210
pr_mock.title = "Title"
211211
pr_mock.get_labels.return_value = [types.SimpleNamespace(name='ask-review')]
@@ -215,7 +215,7 @@ def test_ask_reviews_default_channel(self, slack_mock, gh_mock, get_events_info_
215215
gh_instance = MagicMock()
216216
gh_instance.repo.get_pull.return_value = pr_mock
217217
gh_mock.return_value = gh_instance
218-
get_events_info_mock.return_value = ("actor", None)
218+
ask_review_actor_mock.return_value = "actor"
219219

220220
emoji_list = {'emoji': {'wave': 'url1'}}
221221
slack_client = MagicMock()
@@ -239,10 +239,10 @@ def test_ask_reviews_default_channel(self, slack_mock, gh_mock, get_events_info_
239239
'os.environ',
240240
{'PR_REQUESTED_TEAMS': '[{"slug": "teamx"}, {"slug": "teamy"}]', 'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token'},
241241
)
242-
@patch('tasks.issue.get_events_info')
242+
@patch('tasks.issue.ask_review_actor')
243243
@patch('tasks.issue.GithubAPI')
244244
@patch('slack_sdk.WebClient')
245-
def test_ask_reviews_same_slack_channel(self, slack_mock, gh_mock, get_events_info_mock, print_mock):
245+
def test_ask_reviews_same_slack_channel(self, slack_mock, gh_mock, ask_review_actor_mock, print_mock):
246246
pr_mock = MagicMock()
247247
pr_mock.title = "Some PR"
248248
pr_mock.get_labels.return_value = [types.SimpleNamespace(name='ask-review')]
@@ -252,7 +252,7 @@ def test_ask_reviews_same_slack_channel(self, slack_mock, gh_mock, get_events_in
252252
gh_instance = MagicMock()
253253
gh_instance.repo.get_pull.return_value = pr_mock
254254
gh_mock.return_value = gh_instance
255-
get_events_info_mock.return_value = ("actor", None)
255+
ask_review_actor_mock.return_value = "actor"
256256

257257
emoji_list = {'emoji': {'wave': 'url1', 'waves': 'url2'}}
258258
slack_client = MagicMock()
@@ -269,103 +269,3 @@ def test_ask_reviews_same_slack_channel(self, slack_mock, gh_mock, get_events_in
269269
slack_client.chat_postMessage.assert_called_once()
270270
args, kwargs = slack_client.chat_postMessage.call_args
271271
self.assertEqual(kwargs['channel'], 'chan-shared')
272-
273-
@patch('builtins.print')
274-
@patch(
275-
'os.environ',
276-
{'PR_REQUESTED_TEAMS': '[{"slug": "team1"}, {"slug": "team2"}]', 'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token'},
277-
)
278-
@patch('tasks.issue.get_events_info')
279-
@patch('tasks.issue.GithubAPI')
280-
@patch('slack_sdk.WebClient')
281-
def test_ask_reviews_from_review_request(self, slack_mock, gh_mock, get_events_info_mock, print_mock):
282-
"""Test that when a specific team is requested (review_request event), only that team is notified"""
283-
pr_mock = MagicMock()
284-
pr_mock.title = "Feature PR"
285-
pr_mock.get_labels.return_value = [types.SimpleNamespace(name='ask-review')]
286-
pr_mock.user.login = "someuser"
287-
pr_mock.html_url = "https://github.com/foo/bar/pull/9"
288-
289-
gh_instance = MagicMock()
290-
gh_instance.repo.get_pull.return_value = pr_mock
291-
gh_mock.return_value = gh_instance
292-
# Simulate a review_request event where team1 was specifically requested
293-
get_events_info_mock.return_value = ("actor", "team42")
294-
295-
emoji_list = {'emoji': {'wave': 'url1', 'waves': 'url2'}}
296-
slack_client = MagicMock()
297-
slack_client.emoji_list.return_value = types.SimpleNamespace(data=emoji_list)
298-
slack_mock.return_value = slack_client
299-
300-
# Fill GITHUB_SLACK_REVIEW_MAP
301-
GITHUB_SLACK_REVIEW_MAP['@datadog/team42'] = 'channel42'
302-
GITHUB_SLACK_REVIEW_MAP['@datadog/team2'] = 'channel2'
303-
304-
ask_reviews(MockContext(), 9)
305-
306-
# Only one message should be sent (to team1's channel)
307-
slack_client.chat_postMessage.assert_called_once()
308-
args, kwargs = slack_client.chat_postMessage.call_args
309-
self.assertEqual(kwargs['channel'], 'channel42')
310-
311-
@patch('builtins.print')
312-
@patch(
313-
'os.environ',
314-
{'PR_REQUESTED_TEAMS': '[{"slug": "team1"}, {"slug": "team2"}]', 'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token'},
315-
)
316-
@patch('tasks.issue.get_events_info')
317-
@patch('tasks.issue.GithubAPI')
318-
@patch('slack_sdk.WebClient')
319-
def test_ask_reviews_from_ready_for_review(self, slack_mock, gh_mock, get_events_info_mock, print_mock):
320-
"""Test that when PR is marked as ready_for_review, all requested teams are notified"""
321-
pr_mock = MagicMock()
322-
pr_mock.title = "Draft PR now ready"
323-
pr_mock.get_labels.return_value = [types.SimpleNamespace(name='ask-review')]
324-
pr_mock.user.login = "developer"
325-
pr_mock.html_url = "https://github.com/foo/bar/pull/10"
326-
327-
gh_instance = MagicMock()
328-
gh_instance.repo.get_pull.return_value = pr_mock
329-
gh_mock.return_value = gh_instance
330-
# Simulate a ready_for_review event (team is None)
331-
get_events_info_mock.return_value = ("actor", None)
332-
333-
emoji_list = {'emoji': {'wave': 'url1', 'waves': 'url2'}}
334-
slack_client = MagicMock()
335-
slack_client.emoji_list.return_value = types.SimpleNamespace(data=emoji_list)
336-
slack_mock.return_value = slack_client
337-
338-
# Fill GITHUB_SLACK_REVIEW_MAP
339-
GITHUB_SLACK_REVIEW_MAP['@datadog/team1'] = 'channel1'
340-
GITHUB_SLACK_REVIEW_MAP['@datadog/team2'] = 'channel2'
341-
342-
ask_reviews(MockContext(), 10)
343-
344-
# Both teams should be notified
345-
self.assertEqual(len(slack_client.chat_postMessage.mock_calls), 2)
346-
channels = [call.kwargs['channel'] for call in slack_client.chat_postMessage.mock_calls]
347-
self.assertIn('channel1', channels)
348-
self.assertIn('channel2', channels)
349-
350-
@patch('builtins.print')
351-
@patch(
352-
'os.environ',
353-
{'PR_REQUESTED_TEAMS': '[{"slug": "team1"}]', 'SLACK_DATADOG_AGENT_BOT_TOKEN': 'fake-token'},
354-
)
355-
@patch('tasks.issue.GithubAPI')
356-
def test_ask_reviews_with_no_review_label(self, gh_mock, print_mock):
357-
"""Test that PR with no-review label is skipped"""
358-
pr_mock = MagicMock()
359-
pr_mock.title = "WIP: Experimental changes"
360-
pr_mock.get_labels.return_value = [
361-
types.SimpleNamespace(name='ask-review'),
362-
types.SimpleNamespace(name='no-review'),
363-
]
364-
365-
gh_instance = MagicMock()
366-
gh_instance.repo.get_pull.return_value = pr_mock
367-
gh_mock.return_value = gh_instance
368-
369-
ask_reviews(MockContext(), 11)
370-
371-
print_mock.assert_any_call("This PR has the no-review label, we don't need to ask for reviews.")

0 commit comments

Comments
 (0)