Skip to content

Commit

Permalink
Wrap code in backticks or upload as file if too long
Browse files Browse the repository at this point in the history
  • Loading branch information
rebkwok committed Feb 9, 2024
1 parent 243a983 commit cf19688
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 8 deletions.
18 changes: 14 additions & 4 deletions ebmbot/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,31 @@ def notify_slack(
slack_client, channel, message_text, thread_ts=None, message_format=None
):
"""Send message to Slack."""
msg_kwargs = {"text": str(message_text)}
msg_kwargs = {"text": str(message_text), "thread_ts": thread_ts, "channel": channel}
if message_format == "blocks":
msg_kwargs["blocks"] = message_text

logger.info(
"Sending message", channel=channel, message=message_text, thread_ts=thread_ts
)
# If messages are longer than 4000 characters, Slack will split them over
# multiple messages. This breaks code formatting, so if a message with code
# format is long, we upload it as a file snippet instead
if message_format == "code":
if len(message_text) > 3990:
message_format = "file"
else:
msg_kwargs["text"] = f"```{msg_kwargs['text']}```"

# In case of any unexpected transient exception posting to slack, retry up to 3
# times and then log the error, to avoid errors in scheduled jobs.
attempts = 0
while attempts < 3:
try:
resp = slack_client.chat_postMessage(
channel=channel, thread_ts=thread_ts, **msg_kwargs
)
if message_format == "file":
resp = slack_client.files_upload_v2(content=message_text, **msg_kwargs)
else:
resp = slack_client.chat_postMessage(**msg_kwargs)
return resp.data
except Exception as err:
attempts += 1
Expand Down
9 changes: 7 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ def chat_postMessage(self, *args, **kwargs):
raise Exception("Error notifying slack")


class MockWebClient(WebClient):
def files_upload_v2(self, *args, **kwargs):
return Mock(data={"ok": True})


@dataclass
class MockRecordingClient:
client: WebClient
client: MockWebClient
recorder: Mock


Expand All @@ -58,7 +63,7 @@ def _get_mock_recording_client(client_class, test_recorder):
@pytest.fixture
def mock_client():
test_recorder = Mock()
yield _get_mock_recording_client(WebClient, test_recorder)
yield _get_mock_recording_client(MockWebClient, test_recorder)
cleanup_mock_web_api_server(test_recorder)


Expand Down
17 changes: 16 additions & 1 deletion tests/job_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,22 @@
"python_job_no_output": {
"run_args_template": "python jobs.py hello_world_no_output",
"report_stdout": True,
}
},
"python_job_long_code_output": {
"run_args_template": "python jobs.py long_code_output",
"report_format": "code",
"report_stdout": True,
},
"good_job_with_code": {
"run_args_template": "cat poem",
"report_stdout": True,
"report_format": "code"
},
"good_job_with_file": {
"run_args_template": "cat poem",
"report_stdout": True,
"report_format": "file"
},
},
"slack": [
{
Expand Down
34 changes: 34 additions & 0 deletions tests/test_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,40 @@ def test_job_success_config_with_no_python_file(mock_client):
assert f.read() == ""


def test_job_with_code_format(mock_client):
scheduler.schedule_job("test_good_job_with_code", {}, "channel", TS, 0)
job = scheduler.reserve_job()

do_job(mock_client.client, job)

assert_slack_client_sends_messages(
mock_client.recorder,
messages_kwargs=[
{"channel": "logs", "text": "about to start"},
{
"channel": "channel",
"text": "```the owl and the pussycat\n```",
},
],
message_format="code",
)


def test_job_with_long_code_output_is_uploaded_as_file(mock_client):
scheduler.schedule_job("test_python_job_long_code_output", {}, "channel", TS, 0)
job = scheduler.reserve_job()

do_job(mock_client.client, job)

assert_slack_client_sends_messages(
mock_client.recorder,
messages_kwargs=[
{"channel": "logs", "text": "about to start"},
],
message_format="file",
)


def do_job(client, job):
job_dispatcher = JobDispatcher(client, job, config)
job_dispatcher.do_job()
Expand Down
10 changes: 10 additions & 0 deletions tests/workspace/test/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ def hello_world_blocks_error():
raise Exception("An error was found!")


def long_code_output():
"""
A function that just outputs >4000 characters for
testing long code blocks to be uploaded as files
"""
return "\n".join(["Hello" * 10 for i in range(100)])


def parse_args():
parser = ArgumentParser()
subparsers = parser.add_subparsers(dest="subparser_name")
Expand All @@ -30,6 +38,8 @@ def parse_args():
h3.set_defaults(function=hello_world_blocks_error)
h4 = subparsers.add_parser("hello_world_no_output")
h4.set_defaults(function=hello_world)
h5 = subparsers.add_parser("long_code_output")
h5.set_defaults(function=long_code_output)
return parser.parse_args()


Expand Down
2 changes: 1 addition & 1 deletion workspace/showlogs/show.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ if test -f "$logfile"; then
if [[ "$output" == "" ]]; then
echo "File has no content"
else
echo "\`\`\`$output\`\`\`"
echo "$output"
fi
else
echo "ERROR: $logdir/$filename not found"
Expand Down

0 comments on commit cf19688

Please sign in to comment.