Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send event to DD on merged PR #30627

Merged
merged 11 commits into from
Nov 4, 2024
31 changes: 31 additions & 0 deletions .github/workflows/report-merged-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Report PR merged event to Datadog

name: Report Merged PR

on:
pull_request:
types: closed

permissions: {}

jobs:
if_merged:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4

- name: Setup Python3
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: "3.12.6"
cache: "pip"
cache-dependency-path: '**/requirements*.txt'

pducolin marked this conversation as resolved.
Show resolved Hide resolved
- name: Install python dependencies
run: pip3 install -r requirements.txt

- name: Send merge event to Datadog
run: |
invoke -e github.pr-merge-dd-event-sender -p ${{ github.event.pull_request.number }}
88 changes: 87 additions & 1 deletion tasks/github_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
trigger_macos_workflow,
)
from tasks.libs.common.constants import DEFAULT_BRANCH, DEFAULT_INTEGRATIONS_CORE_BRANCH
from tasks.libs.common.datadog_api import create_gauge, send_metrics
from tasks.libs.common.datadog_api import create_gauge, send_event, send_metrics
from tasks.libs.common.junit_upload_core import repack_macos_junit_tar
from tasks.libs.common.utils import get_git_pretty_ref
from tasks.libs.owners.linter import codeowner_has_orphans, directory_has_packages_without_owner
Expand Down Expand Up @@ -409,3 +409,89 @@ def pr_commenter(

if verbose:
print(f"{action} comment on PR #{pr.number} - {pr.title}")


@task
def pr_merge_dd_event_sender(
_,
pr_id: int | None = None,
dry_run: bool = False,
):
"""
Sends a PR merged event to Datadog with the following tags:
- repo:datadog-agent
- pr:<pr_number>
- author:<pr_author>
- qa_label:missing if the PR doesn't have the qa/done or qa/no-code-change label
- qa_description:missing if the PR doesn't have a test/QA description section

- pr_id: If None, will use $CI_COMMIT_BRANCH to identify which PR
"""

from tasks.libs.ciproviders.github_api import GithubAPI

github = GithubAPI()

if pr_id is None:
branch = os.environ["CI_COMMIT_BRANCH"]
prs = list(github.get_pr_for_branch(branch))
assert len(prs) == 1, f"Expected 1 PR for branch {branch}, found {len(prs)} PRs"
pr = prs[0]
else:
pr = github.get_pr(int(pr_id))

if not pr.merged:
raise Exit(f"PR #{pr.number} is not merged yet", code=1)

tags = [f'repo:{pr.base.repo.full_name}', f'pr_id:{pr.number}', f'author:{pr.user.login}']
labels = set(github.get_pr_labels(pr.number))
all_qa_labels = {'qa/done', 'qa/no-code-change'}
qa_labels = all_qa_labels.intersection(labels)
if len(qa_labels) == 0:
tags.append('qa_label:missing')
else:
tags.extend([f"qa_label:{label}" for label in qa_labels])

qa_description = extract_test_qa_description(pr.body)
if qa_description == '':
tags.append('qa_description:missing')

tags.extend([f"team:{label.removeprefix('team/')}" for label in labels if label.startswith('team/')])
title = "PR merged"
text = f"PR #{pr.number} merged to {pr.base.ref} at {pr.base.repo.full_name} by {pr.user.login} with QA description [{qa_description}]"

if dry_run:
print(f'''I would send the following event to Datadog:

title: {title}
text: {text}
tags: {tags}''')
return

send_event(
title=title,
text=text,
tags=tags,
)


def extract_test_qa_description(pr_body: str) -> str:
"""
Extract the test/QA description section from the PR body
"""
# Extract the test/QA description section from the PR body
# Based on PULL_REQUEST_TEMPLATE.md
pr_body_lines = pr_body.splitlines()
index_of_test_qa_section = -1
for i, line in enumerate(pr_body_lines):
if line.startswith('### Describe how to test'):
index_of_test_qa_section = i
break
index_of_next_section = -1
for i in range(index_of_test_qa_section + 1, len(pr_body_lines)):
if pr_body_lines[i].startswith('### Possible Drawbacks'):
index_of_next_section = i
break
if index_of_next_section == -1:
return ''
return '\n'.join(pr_body_lines[index_of_test_qa_section + 1 : index_of_next_section]).strip()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might handle the case where the first line is not found, so that we avoid returning the full content of the body

29 changes: 29 additions & 0 deletions tasks/libs/common/datadog_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,32 @@ def send_metrics(series):
raise Exit(code=1)

return response


def send_event(title: str, text: str, tags: list[str] = None):
"""
Post an event returns "OK" response
"""

from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v1.api.events_api import EventsApi
from datadog_api_client.v1.model.event_create_request import EventCreateRequest

body = EventCreateRequest(
title=title,
text=text,
tags=tags or [],
)

configuration = Configuration()
with ApiClient(configuration) as api_client:
api_instance = EventsApi(api_client)
response = api_instance.create_event(body=body)

if response["errors"]:
print(
f"Error(s) while sending pipeline event to the Datadog backend: {response['errors']}", file=sys.stderr
)
raise Exit(code=1)

return response
Loading
Loading