From b62cc23d7a61f8cbe7c2c5d8db294f17e9837a8e Mon Sep 17 00:00:00 2001 From: Nicolas Schweitzer Date: Thu, 13 Feb 2025 09:50:02 +0100 Subject: [PATCH] feat(notify): Stop using the slack-notifier base (#33928) --- .../internal_kubernetes_deploy.yml | 10 ++--- .gitlab/notify/notify.yml | 35 +++++++-------- .gitlab/trigger_release/trigger_release.yml | 13 +++--- tasks/github_tasks.py | 6 ++- tasks/libs/notify/alerts.py | 6 ++- tasks/libs/notify/pipeline_status.py | 23 +++++++--- tasks/libs/pipeline/notifications.py | 19 ++------ tasks/notify.py | 11 +++++ tasks/pipeline.py | 8 ++-- tasks/unit_tests/libs/notify/alerts_tests.py | 19 +++++--- tasks/unit_tests/notify_tests.py | 45 ++++++++++++++----- 11 files changed, 117 insertions(+), 78 deletions(-) diff --git a/.gitlab/internal_kubernetes_deploy/internal_kubernetes_deploy.yml b/.gitlab/internal_kubernetes_deploy/internal_kubernetes_deploy.yml index 1762ac56972ae5..d62461c768dd6c 100644 --- a/.gitlab/internal_kubernetes_deploy/internal_kubernetes_deploy.yml +++ b/.gitlab/internal_kubernetes_deploy/internal_kubernetes_deploy.yml @@ -2,9 +2,6 @@ # internal_kubernetes_deploy stage # Contains jobs to trigger a pipeline in our k8s-datadog-agent-ops repo -include: - - https://gitlab-templates.ddbuild.io/slack-notifier/v3-sdm/template.yml - internal_kubernetes_deploy_experimental: stage: internal_kubernetes_deploy rules: @@ -68,7 +65,7 @@ internal_kubernetes_deploy_experimental: notify-slack: stage: internal_kubernetes_deploy - extends: .slack-notifier-base + image: registry.ddbuild.io/ci/datadog-agent-buildimages/deb_arm64$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES rules: - if: $FORCE_K8S_DEPLOYMENT == "true" when: always @@ -79,9 +76,10 @@ notify-slack: - if: $APPS !~ "/^datadog-agent/" when: never - !reference [.on_deploy] - tags: ["arch:amd64"] + tags: ["arch:arm64"] needs: ["internal_kubernetes_deploy_experimental"] script: - export SDM_JWT=$(vault read -field=token identity/oidc/token/sdm) - - python3 -m pip install -r tasks/requirements.txt + - python3 -m pip install -r tasks/requirements.txt -r tasks/libs/requirements-notifications.txt + - SLACK_API_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $SLACK_AGENT token) || exit $?; export SLACK_API_TOKEN - inv pipeline.changelog ${CI_COMMIT_SHORT_SHA} || exit $? diff --git a/.gitlab/notify/notify.yml b/.gitlab/notify/notify.yml index 218fc520619089..72c55adbd23ae0 100644 --- a/.gitlab/notify/notify.yml +++ b/.gitlab/notify/notify.yml @@ -2,32 +2,35 @@ # notify stage # Contains jobs which send notifications depending on pipeline status. -include: - - https://gitlab-templates.ddbuild.io/slack-notifier/v3-sdm/template.yml +.notify_setup: + - SLACK_API_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $SLACK_AGENT token) || exit $?; export SLACK_API_TOKEN + - GITLAB_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $GITLAB_TOKEN read_api) || exit $?; export GITLAB_TOKEN + - DD_API_KEY=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $AGENT_API_KEY_ORG2 token) || exit $?; export DD_API_KEY + - python3 -m pip install -r requirements.txt -r tasks/libs/requirements-notifications.txt notify-on-tagged-success: - extends: .slack-notifier-base stage: notify + image: registry.ddbuild.io/ci/datadog-agent-buildimages/deb_arm64$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES rules: !reference [.on_deploy_stable_or_beta_repo_branch] dependencies: [] - tags: ["arch:amd64"] + tags: ["arch:arm64"] script: | MESSAGE_TEXT=":host-green: Tagged build <$CI_PIPELINE_URL|$CI_PIPELINE_ID> succeeded. *$CI_COMMIT_REF_NAME* is available in the staging repositories." - postmessage "#agent-release-sync" "$MESSAGE_TEXT" + python3 -m pip install -r requirements.txt -r tasks/libs/requirements-notifications.txt + SLACK_API_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $SLACK_AGENT token) || exit $?; export SLACK_API_TOKEN + invoke notify.post-message -c "#agent-release-sync" -m "$MESSAGE_TEXT" notify: - extends: .slack-notifier-base stage: notify + image: registry.ddbuild.io/ci/datadog-agent-buildimages/deb_arm64$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES rules: !reference [.on_main_or_release_branch_or_deploy_always] dependencies: [] - tags: ["arch:amd64"] + tags: ["arch:arm64"] resource_group: notification timeout: 15 minutes # Added to prevent a stuck job blocking the resource_group defined above script: - - GITLAB_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $GITLAB_TOKEN read_api) || exit $?; export GITLAB_TOKEN - - DD_API_KEY=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $AGENT_API_KEY_ORG2 token) || exit $?; export DD_API_KEY - - python3 -m pip install -r requirements.txt -r tasks/libs/requirements-notifications.txt + - !reference [.notify_setup] - invoke -e notify.send-message -p $CI_PIPELINE_ID - invoke -e notify.check-consistent-failures -p $CI_PIPELINE_ID @@ -38,8 +41,7 @@ send_pipeline_stats: when: always dependencies: [] script: - - GITLAB_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $GITLAB_TOKEN read_api) || exit $?; export GITLAB_TOKEN - - DD_API_KEY=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $AGENT_API_KEY_ORG2 token) || exit $?; export DD_API_KEY + - !reference [.notify_setup] - invoke -e notify.send-stats notify_github: @@ -105,11 +107,6 @@ notify_gitlab_ci_changes: resource_group: notification timeout: 15 minutes # Added to prevent a stuck job blocking the resource_group defined above -.failure_summary_setup: - - SLACK_API_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $SLACK_AGENT token) || exit $?; export SLACK_API_TOKEN - - GITLAB_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $GITLAB_TOKEN read_api) || exit $?; export GITLAB_TOKEN - - DD_API_KEY=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $AGENT_API_KEY_ORG2 token) || exit $?; export DD_API_KEY - - python3 -m pip install -r requirements.txt -r tasks/libs/requirements-notifications.txt # Upload failure summary data to S3 at the end of each main pipeline notify_failure_summary_on_pipeline: @@ -119,7 +116,7 @@ notify_failure_summary_on_pipeline: when: never - !reference [.on_main_always] script: - - !reference [.failure_summary_setup] + - !reference [.notify_setup] - inv -e notify.failure-summary-upload-pipeline-data # Send failure summary notifications daily and weekly @@ -130,7 +127,7 @@ notify_failure_summary_daily: when: never - !reference [.on_deploy_nightly_repo_branch_always] script: - - !reference [.failure_summary_setup] + - !reference [.notify_setup] - weekday="$(date --utc '+%A')" - | if [ "$weekday" = "Sunday" ] || [ "$weekday" = "Monday" ]; then diff --git a/.gitlab/trigger_release/trigger_release.yml b/.gitlab/trigger_release/trigger_release.yml index 9dc92f30fa6c29..f4421c03de1c61 100644 --- a/.gitlab/trigger_release/trigger_release.yml +++ b/.gitlab/trigger_release/trigger_release.yml @@ -77,9 +77,6 @@ trigger_manual_prod_release_on_failure: when: never - !reference [.on_deploy_stable_on_failure] -include: - - https://gitlab-templates.ddbuild.io/slack-notifier/v3-sdm/template.yml - .setup_github_app_agent_platform_auto_pr: # GitHub App rate-limits are per-app. Since we are rarely calling the job, we are only using the instance 2 - | @@ -90,9 +87,9 @@ include: generate_windows_gitlab_runner_bump_pr: stage: trigger_release - extends: .slack-notifier-base + image: registry.ddbuild.io/ci/datadog-agent-buildimages/deb_arm64$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES needs: ["trigger_auto_staging_release"] - tags: ["arch:amd64"] + tags: ["arch:arm64"] rules: - if: $DDR_WORKFLOW_ID != null when: never @@ -105,14 +102,15 @@ generate_windows_gitlab_runner_bump_pr: - !reference [.setup_github_app_agent_platform_auto_pr] - python3 -m pip install -r requirements.txt -r tasks/libs/requirements-notifications.txt - $S3_CP_CMD $S3_ARTIFACTS_URI/agent-version.cache . + - SLACK_API_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $SLACK_AGENT token) || exit $?; export SLACK_API_TOKEN - inv -e github.update-windows-runner-version # Manual job to generate the gitlab bump pr on buildenv if trigger_auto_staging_release fails generate_windows_gitlab_runner_bump_pr_manual: stage: trigger_release - extends: .slack-notifier-base + image: registry.ddbuild.io/ci/datadog-agent-buildimages/deb_arm64$DATADOG_AGENT_BUILDIMAGES_SUFFIX:$DATADOG_AGENT_BUILDIMAGES needs: ["trigger_auto_staging_release"] - tags: ["arch:amd64"] + tags: ["arch:arm64"] rules: - if: $DDR_WORKFLOW_ID != null when: never @@ -125,4 +123,5 @@ generate_windows_gitlab_runner_bump_pr_manual: - !reference [.setup_github_app_agent_platform_auto_pr] - python3 -m pip install -r requirements.txt -r tasks/libs/requirements-notifications.txt - $S3_CP_CMD $S3_ARTIFACTS_URI/agent-version.cache . + - SLACK_API_TOKEN=$($CI_PROJECT_DIR/tools/ci/fetch_secret.sh $SLACK_AGENT token) || exit $?; export SLACK_API_TOKEN - inv -e github.update-windows-runner-version diff --git a/tasks/github_tasks.py b/tasks/github_tasks.py index ac291c42b515ed..7ec8e524a97896 100644 --- a/tasks/github_tasks.py +++ b/tasks/github_tasks.py @@ -25,7 +25,6 @@ from tasks.libs.common.datadog_api import create_gauge, send_event, send_metrics from tasks.libs.common.git import get_default_branch from tasks.libs.common.utils import get_git_pretty_ref -from tasks.libs.notify.pipeline_status import send_slack_message from tasks.libs.owners.linter import codeowner_has_orphans, directory_has_packages_without_owner from tasks.libs.owners.parsing import read_owners from tasks.libs.pipeline.notifications import GITHUB_SLACK_MAP @@ -143,7 +142,10 @@ def _update_windows_runner_version(new_version=None, buildenv_ref="master"): message = f":robobits: A new windows-runner bump PR to {new_version} has been generated. Please take a look :frog-review:\n:pr: {PR_URL} :ty:" - send_slack_message("ci-infra-support", message) + from slack_sdk import WebClient + + client = WebClient(token=os.environ["SLACK_API_TOKEN"]) + client.chat_postMessage(channel="ci-infra-support", text=message) return workflow_conclusion diff --git a/tasks/libs/notify/alerts.py b/tasks/libs/notify/alerts.py index f70ea88279cda2..1c7ab7bb8eb9ef 100644 --- a/tasks/libs/notify/alerts.py +++ b/tasks/libs/notify/alerts.py @@ -19,7 +19,6 @@ from tasks.libs.pipeline.data import get_failed_jobs from tasks.libs.pipeline.notifications import ( get_pr_from_commit, - send_slack_message, ) from tasks.owners import channel_owners, make_partition @@ -232,7 +231,10 @@ def send_alert(channel, consecutive: ConsecutiveJobAlert, cumulative: Cumulative message = message.strip() if message: - send_slack_message(channel, message) + from slack_sdk import WebClient + + client = WebClient(token=os.environ["SLACK_API_TOKEN"]) + client.chat_postMessage(channel=channel, text=message) # Create metrics for consecutive and cumulative alerts return [ diff --git a/tasks/libs/notify/pipeline_status.py b/tasks/libs/notify/pipeline_status.py index 420577b98ab5fd..89e3c7408fbd81 100644 --- a/tasks/libs/notify/pipeline_status.py +++ b/tasks/libs/notify/pipeline_status.py @@ -1,14 +1,15 @@ +import os import re +import sys from tasks.libs.ciproviders.gitlab_api import get_commit, get_pipeline from tasks.libs.common.git import get_default_branch +from tasks.libs.common.utils import Color, color_message from tasks.libs.notify.utils import DEPLOY_PIPELINES_CHANNEL, PIPELINES_CHANNEL, PROJECT_NAME, get_pipeline_type from tasks.libs.pipeline.data import get_failed_jobs from tasks.libs.pipeline.notifications import ( base_message, - email_to_slackid, get_failed_tests, - send_slack_message, ) from tasks.libs.types.types import SlackMessage @@ -58,16 +59,26 @@ def send_message(ctx, pipeline_id, dry_run): for test in get_failed_tests(PROJECT_NAME, job): message.add_test_failure(test, job) - # Send messages + # Send message + from slack_sdk import WebClient + from slack_sdk.errors import SlackApiError + + client = WebClient(token=os.environ["SLACK_API_TOKEN"]) if dry_run: print(f"Would send to {slack_channel}:\n{str(message)}") else: - send_slack_message(slack_channel, str(message)) + client.chat_postMessage(channel=slack_channel, text=str(message)) if should_send_message_to_author(pipeline.ref, get_default_branch()): author_email = commit.author_email if dry_run: print(f"Would send to {author_email}:\n{str(message)}") else: - recipient = email_to_slackid(ctx, author_email) - send_slack_message(recipient, str(message)) + try: + recipient = client.users_lookupByEmail(email=author_email) + client.chat_postMessage(channel=recipient.data['user']['id'], text=str(message)) + except SlackApiError as e: + print( + f"[{color_message('ERROR', Color.RED)}] Failed to send message to {author_email}: {e.response['error']}", + file=sys.stderr, + ) diff --git a/tasks/libs/pipeline/notifications.py b/tasks/libs/pipeline/notifications.py index 5193e219660a61..b28f1597ce2e86 100644 --- a/tasks/libs/pipeline/notifications.py +++ b/tasks/libs/pipeline/notifications.py @@ -4,14 +4,12 @@ import os import pathlib import re -import subprocess from collections import defaultdict from datetime import datetime, timezone import gitlab import yaml from gitlab.v4.objects import ProjectCommit, ProjectJob, ProjectPipeline -from invoke.context import Context from tasks.libs.ciproviders.gitlab_api import get_gitlab_repo from tasks.libs.owners.parsing import read_owners @@ -157,6 +155,9 @@ def base_message(project_name: str, pipeline: ProjectPipeline, commit: ProjectCo commit_url_github = f"{GITHUB_BASE_URL}/{project_name}/commit/{commit.id}" commit_short_sha = commit.id[-8:] author = commit.author_name + finish = datetime.fromisoformat(pipeline.finished_at) if pipeline.finished_at else datetime.now(timezone.utc) + delta = finish - datetime.fromisoformat(pipeline.started_at) + duration = f"[:hourglass: {int(delta.total_seconds() / 60)} min]" # Try to find a PR id (e.g #12345) in the commit title and add a link to it in the message if found. pr_info = get_pr_from_commit(commit_title, project_name) @@ -165,22 +166,10 @@ def base_message(project_name: str, pipeline: ProjectPipeline, commit: ProjectCo parsed_pr_id, pr_url_github = pr_info enhanced_commit_title = enhanced_commit_title.replace(f"#{parsed_pr_id}", f"<{pr_url_github}|#{parsed_pr_id}>") - return f"""{header} pipeline <{pipeline_url}|{pipeline_id}> for {commit_ref_name} {state}. + return f"""{header} pipeline <{pipeline_url}|{pipeline_id}> for {commit_ref_name} {state} {duration}. {enhanced_commit_title} (<{commit_url_gitlab}|{commit_short_sha}>)(:github: <{commit_url_github}|link>) by {author}""" -def send_slack_message(recipient, message): - subprocess.run(["postmessage", recipient, message], check=True) - - -def email_to_slackid(ctx: Context, email: str) -> str: - slackid = ctx.run(f"echo '{email}' | email2slackid", hide=True, warn=True).stdout.strip() - - assert slackid != '', 'Email not found' - - return slackid - - def warn_new_commits(release_managers, team, branch, next_rc): from slack_sdk import WebClient diff --git a/tasks/notify.py b/tasks/notify.py index 33dbacecc6f1cf..93d78fe244191d 100644 --- a/tasks/notify.py +++ b/tasks/notify.py @@ -277,3 +277,14 @@ def close_failing_tests_stale_issues(_, dry_run=False): print(f'Error closing issue {issue["key"]}: {e}', file=sys.stderr) print(f'Closed {n_closed} issues without failing tests') + + +@task +def post_message(_: Context, channel: str, message: str): + """ + Post a message to a slack channel + """ + from slack_sdk import WebClient + + client = WebClient(token=os.environ['SLACK_API_TOKEN']) + client.chat_postMessage(channel=channel, text=message) diff --git a/tasks/pipeline.py b/tasks/pipeline.py index 38cd4d0a42b43b..264c12693075a0 100644 --- a/tasks/pipeline.py +++ b/tasks/pipeline.py @@ -26,7 +26,6 @@ is_allowed_repo_branch, ) from tasks.libs.owners.parsing import read_owners -from tasks.libs.pipeline.notifications import send_slack_message from tasks.libs.pipeline.tools import ( FilteredOutException, cancel_pipelines_with_confirmation, @@ -475,6 +474,9 @@ def is_system_probe(owners, files): @task def changelog(ctx, new_commit_sha): + from slack_sdk import WebClient + + client = WebClient(token=os.environ["SLACK_API_TOKEN"]) # Environment variable to deal with both local and CI environments if "CI_PROJECT_DIR" in os.environ: parent_dir = os.environ["CI_PROJECT_DIR"] @@ -502,7 +504,7 @@ def changelog(ctx, new_commit_sha): if old_commit_sha == new_commit_sha: print("No new commits found, exiting") slack_message += no_commits_msg - send_slack_message("system-probe-ops", slack_message) + client.chat_postMessage(channel="system-probe-ops", text=slack_message) return print(f"Generating changelog for commit range {old_commit_sha} to {new_commit_sha}") @@ -543,7 +545,7 @@ def changelog(ctx, new_commit_sha): slack_message += empty_changelog_msg print(f"Posting message to slack: \n {slack_message}") - send_slack_message("system-probe-ops", slack_message) + client.chat_postMessage(channel="system-probe-ops", text=slack_message) print(f"Writing new commit sha: {new_commit_sha} to SSM") res = ctx.run( f"aws ssm put-parameter --name ci.datadog-agent.gitlab_changelog_commit_sha --value {new_commit_sha} " diff --git a/tasks/unit_tests/libs/notify/alerts_tests.py b/tasks/unit_tests/libs/notify/alerts_tests.py index e80caed24ef2fb..3abf0171ecfa48 100644 --- a/tasks/unit_tests/libs/notify/alerts_tests.py +++ b/tasks/unit_tests/libs/notify/alerts_tests.py @@ -219,19 +219,24 @@ def test_cumulative(self): message = cumulative.message() self.assertIn(f'{alerts.CUMULATIVE_THRESHOLD} times in last {alerts.CUMULATIVE_LENGTH} executions', message) - @patch("tasks.libs.notify.alerts.send_slack_message") + @patch('slack_sdk.WebClient', autospec=True) def test_none(self, mock_slack): + client_mock = MagicMock() + mock_slack.return_value = client_mock alert_jobs = {"consecutive": {}, "cumulative": {}} alerts.send_notification(MagicMock(), alert_jobs) - mock_slack.assert_not_called() + client_mock.chat_postMessage.assert_not_called() @patch("tasks.libs.notify.alerts.send_metrics") - @patch("tasks.libs.notify.alerts.send_slack_message") - @patch.object(alerts.ConsecutiveJobAlert, 'message', lambda self, ctx: '\n'.join(self.failures) + '\n') + @patch('slack_sdk.WebClient', autospec=True) + @patch.dict('os.environ', {'SLACK_API_TOKEN': 'coucou'}) + @patch.object(alerts.ConsecutiveJobAlert, 'message', lambda self, _: '\n'.join(self.failures) + '\n') @patch.object(alerts.CumulativeJobAlert, 'message', lambda self: '\n'.join(self.failures)) @patch('tasks.owners.GITHUB_SLACK_MAP', get_github_slack_map()) @patch('tasks.libs.notify.alerts.CHANNEL_BROADCAST', '#channel-broadcast') def test_jobowners(self, mock_slack: MagicMock, mock_metrics: MagicMock): + client_mock = MagicMock() + mock_slack.return_value = client_mock consecutive = { 'tests_hello': [alerts.ExecutionsJobInfo(1)] * alerts.CONSECUTIVE_THRESHOLD, 'tests_team_a_1': [alerts.ExecutionsJobInfo(1)] * alerts.CONSECUTIVE_THRESHOLD, @@ -248,7 +253,7 @@ def test_jobowners(self, mock_slack: MagicMock, mock_metrics: MagicMock): alert_jobs = {"consecutive": consecutive, "cumulative": cumulative} alerts.send_notification(MagicMock(), alert_jobs, jobowners='tasks/unit_tests/testdata/jobowners.txt') - self.assertEqual(len(mock_slack.call_args_list), 4) + self.assertEqual(len(client_mock.chat_postMessage.call_args_list), 4) # Verify that we send the right number of jobs per channel expected_team_njobs = { @@ -258,8 +263,8 @@ def test_jobowners(self, mock_slack: MagicMock, mock_metrics: MagicMock): '#channel-broadcast': 5, } - for call_args in mock_slack.call_args_list: - channel, message = call_args.args + for call_args in client_mock.chat_postMessage.call_args_list: + channel, message = call_args.kwargs['channel'], call_args.kwargs['text'] # The mock will separate job names with a newline jobs = message.strip().split("\n") njobs = len(jobs) diff --git a/tasks/unit_tests/notify_tests.py b/tasks/unit_tests/notify_tests.py index f130f9d346d123..9700042a36b1a3 100644 --- a/tasks/unit_tests/notify_tests.py +++ b/tasks/unit_tests/notify_tests.py @@ -32,6 +32,7 @@ def get_github_slack_map(): class TestSendMessage(unittest.TestCase): @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) + @patch('slack_sdk.WebClient', new=MagicMock()) @patch('builtins.print') @patch('tasks.libs.ciproviders.gitlab_api.get_gitlab_api') def test_merge(self, api_mock, print_mock): @@ -40,25 +41,30 @@ def test_merge(self, api_mock, print_mock): repo_mock.jobs.get.return_value.trace.return_value = b"Log trace" repo_mock.pipelines.get.return_value.ref = "test" repo_mock.pipelines.get.return_value.source = "push" + repo_mock.pipelines.get.return_value.started_at = "2025-02-07T05:59:48.396Z" + repo_mock.pipelines.get.return_value.finished_at = "2025-02-07T06:59:48.396Z" list_mock = repo_mock.pipelines.get.return_value.jobs.list list_mock.side_effect = [get_fake_jobs(), []] - with patch.dict('os.environ', {}, clear=True): + with patch.dict('os.environ', {'SLACK_API_TOKEN': 'coin'}, clear=True): notify.send_message(MockContext(), "42", dry_run=True) list_mock.assert_called() repo_mock.pipelines.get.assert_called_with("42") self.assertTrue("merge" in print_mock.mock_calls[0].args[0]) repo_mock.jobs.get.assert_called() + @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) + @patch('slack_sdk.WebClient', new=MagicMock()) @patch('tasks.libs.ciproviders.gitlab_api.get_gitlab_api') @patch('tasks.libs.notify.pipeline_status.get_failed_jobs') @patch('builtins.print') - @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) def test_merge_without_get_failed_call(self, print_mock, get_failed_jobs_mock, api_mock): repo_mock = api_mock.return_value.projects.get.return_value repo_mock.jobs.get.return_value.artifact.return_value = b"{}" repo_mock.jobs.get.return_value.trace.return_value = b"Log trace" repo_mock.pipelines.get.return_value.ref = "test" repo_mock.pipelines.get.return_value.source = "push" + repo_mock.pipelines.get.return_value.started_at = "2025-02-07T05:59:48.396Z" + repo_mock.pipelines.get.return_value.finished_at = "2025-02-07T06:59:48.396Z" failed = FailedJobs() failed.add_failed_job( @@ -122,7 +128,7 @@ def test_merge_without_get_failed_call(self, print_mock, get_failed_jobs_mock, a ) ) get_failed_jobs_mock.return_value = failed - with patch.dict('os.environ', {}, clear=True): + with patch.dict('os.environ', {'SLACK_API_TOKEN': 'meuh'}, clear=True): notify.send_message(MockContext(), "42", dry_run=True) self.assertTrue("merge" in print_mock.mock_calls[0].args[0]) get_failed_jobs_mock.assert_called() @@ -201,9 +207,10 @@ def test_route_e2e_internal_error(self, read_owners_mock): self.assertNotIn("@DataDog/agent-devx-loops", owners) self.assertNotIn("@DataDog/agent-delivery", owners) + @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) + @patch('slack_sdk.WebClient', new=MagicMock()) @patch('tasks.libs.ciproviders.gitlab_api.get_gitlab_api') @patch('builtins.print') - @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) def test_merge_with_get_failed_call(self, print_mock, api_mock): repo_mock = api_mock.return_value.projects.get.return_value trace_mock = repo_mock.jobs.get.return_value.trace @@ -214,18 +221,21 @@ def test_merge_with_get_failed_call(self, print_mock, api_mock): repo_mock.jobs.get.return_value.artifact.return_value = b"{}" repo_mock.pipelines.get.return_value.ref = "test" repo_mock.pipelines.get.return_value.source = "push" + repo_mock.pipelines.get.return_value.started_at = "2025-02-07T05:59:48.396Z" + repo_mock.pipelines.get.return_value.finished_at = None - with patch.dict('os.environ', {}, clear=True): + with patch.dict('os.environ', {'SLACK_API_TOKEN': 'ouaf'}, clear=True): notify.send_message(MockContext(), "42", dry_run=True) self.assertTrue("merge" in print_mock.mock_calls[0].args[0]) trace_mock.assert_called() list_mock.assert_called() repo_mock.jobs.get.assert_called() - @patch.dict('os.environ', {'DEPLOY_AGENT': 'true'}) + @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) + @patch('slack_sdk.WebClient', new=MagicMock()) + @patch.dict('os.environ', {'DEPLOY_AGENT': 'true', 'SLACK_API_TOKEN': 'hihan'}) @patch('tasks.libs.ciproviders.gitlab_api.get_gitlab_api') @patch('builtins.print') - @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) def test_deploy_with_get_failed_call(self, print_mock, api_mock): repo_mock = api_mock.return_value.projects.get.return_value trace_mock = repo_mock.jobs.get.return_value.trace @@ -236,16 +246,20 @@ def test_deploy_with_get_failed_call(self, print_mock, api_mock): repo_mock.jobs.get.return_value.artifact.return_value = b"{}" repo_mock.pipelines.get.return_value.ref = "test" repo_mock.pipelines.get.return_value.source = "push" + repo_mock.pipelines.get.return_value.started_at = "2025-02-07T05:59:48.396Z" + repo_mock.pipelines.get.return_value.finished_at = "2025-02-07T08:21:48.396Z" notify.send_message(MockContext(), "42", dry_run=True) self.assertTrue("rocket" in print_mock.mock_calls[0].args[0]) + self.assertTrue("[:hourglass: 142 min]" in print_mock.mock_calls[0].args[0]) trace_mock.assert_called() list_mock.assert_called() repo_mock.jobs.get.assert_called() + @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) + @patch('slack_sdk.WebClient', new=MagicMock()) @patch('tasks.libs.ciproviders.gitlab_api.get_gitlab_api') @patch('builtins.print') - @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) def test_trigger_with_get_failed_call(self, print_mock, api_mock): repo_mock = api_mock.return_value.projects.get.return_value trace_mock = repo_mock.jobs.get.return_value.trace @@ -256,18 +270,24 @@ def test_trigger_with_get_failed_call(self, print_mock, api_mock): repo_mock.jobs.get.return_value.artifact.return_value = b"{}" repo_mock.pipelines.get.return_value.ref = "test" repo_mock.pipelines.get.return_value.source = "api" + repo_mock.pipelines.get.return_value.started_at = "2025-02-07T05:59:48.396Z" + repo_mock.pipelines.get.return_value.finished_at = "2025-02-07T06:59:48.396Z" - with patch.dict('os.environ', {}, clear=True): + with patch.dict('os.environ', {'SLACK_API_TOKEN': 'miaou'}, clear=True): notify.send_message(MockContext(), "42", dry_run=True) self.assertTrue("arrow_forward" in print_mock.mock_calls[0].args[0]) + self.assertTrue("[:hourglass: 60 min]" in print_mock.mock_calls[0].args[0]) trace_mock.assert_called() list_mock.assert_called() repo_mock.jobs.get.assert_called() - @patch.dict('os.environ', {'DDR': 'true', 'DDR_WORKFLOW_ID': '1337', 'DEPLOY_AGENT': 'false'}) + @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) + @patch('slack_sdk.WebClient', new=MagicMock()) + @patch.dict( + 'os.environ', {'DDR': 'true', 'DDR_WORKFLOW_ID': '1337', 'DEPLOY_AGENT': 'false', 'SLACK_API_TOKEN': 'ni'} + ) @patch('tasks.libs.ciproviders.gitlab_api.get_gitlab_api') @patch('builtins.print') - @patch('tasks.libs.pipeline.notifications.get_pr_from_commit', new=MagicMock(return_value="")) def test_trigger_with_get_failed_call_conductor(self, print_mock, api_mock): repo_mock = api_mock.return_value.projects.get.return_value trace_mock = repo_mock.jobs.get.return_value.trace @@ -278,9 +298,12 @@ def test_trigger_with_get_failed_call_conductor(self, print_mock, api_mock): repo_mock.jobs.get.return_value.artifact.return_value = b"{}" repo_mock.pipelines.get.return_value.ref = "test" repo_mock.pipelines.get.return_value.source = "pipeline" + repo_mock.pipelines.get.return_value.started_at = "2025-02-07T05:59:48.396Z" + repo_mock.pipelines.get.return_value.finished_at = "2025-02-07T06:41:48.396Z" notify.send_message(MockContext(), "42", dry_run=True) self.assertTrue("arrow_forward" in print_mock.mock_calls[0].args[0]) + self.assertTrue("[:hourglass: 42 min]" in print_mock.mock_calls[0].args[0]) trace_mock.assert_called() list_mock.assert_called() repo_mock.jobs.get.assert_called()