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

Support updating corresponding comment message in Slack #132

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

sewenthy
Copy link
Contributor

@sewenthy sewenthy commented Mar 13, 2023

Description of the task

Make monorobot remember each comment it sends to slack and then update the comment if the comment was edited in github.

Supports edits in:

  • PR review comment
  • PR review
  • Issue comment

Commit comment edits do not send an edited event.

All PRs are numbered uniquely with issue numbers so tracking these events as issues. Clean up from state when PR is closed (not supporting comment edits after PR is closed/merged).

How to test

monorobot $ make test

References

Copy link
Collaborator

@yasunariw yasunariw left a comment

Choose a reason for hiding this comment

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

Please check the unexpected test output.

lib/slack.ml Outdated
Comment on lines 115 to 118
( match State.get_review_msg ctx.state repository.url ~issue_num:number review.id with
| Some ({ channel; ts } : post_message_res) ->
Update_message { channel; ts; text = Some summary; attachments; blocks = None }
| None -> invalid_arg (sprintf "could not find review %d in %s for PR #%n" review.id repository.url number)
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. I prefer this function stays pure; the caller can do the stateful lookup and pass only an optional ts value (and not the entire ctx) to this function. Same for the others below.
  2. The channel is overwritten with the value from the cached post_message_res, which I think is the cause of the bug in the new tests.
  3. I think we should log, not fail, when message ts is not found. Because such a case is not unexpected, according to the PR description.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Unrelated to this PR, but observing that that these functions are called once for each channel, and most of it can be staged, as only the last part depends on channel value.

(** [update_notification ctx msg] update a message at [msg.ts] in [msg.channel]
with the payload [msg]; uses web API with access token if available, or with
webhook otherwise *)
let update_notification ~(ctx : Context.t) ~(msg : Slack_t.update_message_req) =
Copy link
Collaborator

@yasunariw yasunariw Apr 7, 2023

Choose a reason for hiding this comment

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

this function is mostly copy pasted from the one above:(

should be able to factor

lib/slack.atd Outdated
Comment on lines 71 to 81
type update_message_req = {
channel: string;
ts: string;
?text: string nullable;
?attachments: message_attachment list nullable;
?blocks: message_block list nullable;
}

type update_message_res = {
channel: string;
ts: string;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure we need these additional types (or the corresponding New_message/Update_message). Maybe ts can be optional field in post_message_req, and Api.send_notification can query either chat.postMessage or chat.update depending on its presence/absence?

Copy link
Collaborator

Choose a reason for hiding this comment

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

On second thought, chat.postMessage and chat.update differ in more than the ts field, so separate type seems warranted.

But for now, that is the only difference, so you can do

type update_message_req = {
  inherit post_message_req;
  ts: string;
}

or have a common base that both inherit from.

lib/state.atd Outdated
}

(* The runtime state of a given GitHub repository
NB: issue number is the same as PR number for github APIs
Copy link
Collaborator

Choose a reason for hiding this comment

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

this detail should be a comment next to the issue_tbl field

@@ -34,6 +38,36 @@ let set_repo_pipeline_status { state; lock } repo_url ~pipeline ~(branches : Git
repo_state.pipeline_statuses <- Map.update repo_state.pipeline_statuses pipeline ~f:set_branch_status;
Lwt.return_unit

let add_comment_msg { state; lock } repo_url ~issue_num comment_id post_message_res =
Lwt_mutex.with_lock lock @@ fun () ->
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this lock is actually unnecessary, not sure why I added it. Anyway, not the concern of this PR.

Comment on lines +206 to +211
| Github.PR_review_comment n ->
State.add_comment_msg ctx.state n.repository.url ~issue_num:n.pull_request.number n.comment.id message
| Issue_comment n ->
State.add_comment_msg ctx.state n.repository.url ~issue_num:n.issue.number n.comment.id message
| PR_review n ->
State.add_review_msg ctx.state n.repository.url ~issue_num:n.pull_request.number n.review.id message
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe the state lookup + update belongs in partition_pr_review_comment etc instead of here

lib/state.atd Outdated
@@ -10,13 +10,23 @@ type branch_statuses = status_state map_as_object
branch *)
type pipeline_statuses = branch_statuses map_as_object

(* The runtime state of a given GitHub repository *)
type post_message_res <ocaml from="Slack"> = abstract
type post_msg_map = post_message_res map_as_object
Copy link
Collaborator

Choose a reason for hiding this comment

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

A message can be posted to multiple Slack channels. The value of this map should be the message ts only, not post_message_res.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

wait then don't we need post_message_res list to update all the ts for each of the channel?

lib/github.atd Outdated
@@ -287,7 +288,7 @@ type api_commit = {
}

type commit_comment_notification = {
action: string;
action: comment_action;
Copy link
Collaborator

Choose a reason for hiding this comment

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

according to the PR description, commit comment edits do not send an edited event.

@@ -171,6 +171,34 @@ will notify #frontend-bot
]
}
===== file ../mock_payloads/issue_comment.edited.json =====
will update msg in #some channel
{
"channel": "some channel",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Test output looks wrong, "some channel" is notified twice. If it is the same mock pr as issue_comment.created_in_pr, it should notify #a1-bot and #backend. Same for the other new tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

o... thanks for the catch!

"comments": {
"0": {
"channel": "some channel",
"ts": "some ts"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can the mock state be more realistic? The current one should be impossible, since there would never be two different messages posted to the same channel with the same ts. Same for the others

@yasunariw
Copy link
Collaborator

yasunariw commented Apr 7, 2023

Curious what's the behavior when the workspace has editing time limit configured and chat.update is called after limit has passed.

I also wonder if there should be periodic cleanup of stale comment timestamps, edit notifications not useful beyond 1 day max?

@sewenthy sewenthy force-pushed the sewen/update-comments-once-edited branch from ef5e936 to 0bfc75d Compare April 22, 2023 06:00
partition_issue_comment cfg n |> List.map ~f:(generate_issue_comment_notification n) |> Lwt.return
partition_issue_comment cfg n
|> List.map ~f:(fun channel ->
(* not sure why but when I remove "fun channel" it evaluates the [generate_issue_comment_notification_content n] before the partition so I got errors but when I add this, it's completely fine, probably some compiler optimization? *)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@yasunariw @Khady any idea why? from what I understand, even without making it an explicit function, the partial evaluation of f should happen after the list generation right?

@sewenthy
Copy link
Contributor Author

edit notifications not useful beyond 1 day max?

we were trying to find the right level of restrictions, I think waiting til a PR is closed is good because we might comment and change after re-visiting so keeping state for the whole time but TBH no strong preference for me 1-day max is also good, if you feel strongly about that then I can change the duration!

@sewenthy
Copy link
Contributor Author

Curious what's the behavior when the workspace has editing time limit configured and chat.update is called after limit has passed.

Just tested, and bot can edit their own message after the workspace editing time passed. Thanks for the catch!

@Khady
Copy link
Contributor

Khady commented Mar 20, 2024

what's the status on this one?

@sewenthy
Copy link
Contributor Author

@Khady I lost track of this, will need to rebase and do some more work. If I remember correctly, I needed to fix the mapping for editing the messages since there can be multiple messages sent to different channels for one single PR.

@Khady Khady added the Blocked label Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants