-
Notifications
You must be signed in to change notification settings - Fork 6
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
base: master
Are you sure you want to change the base?
Support updating corresponding comment message in Slack #132
Conversation
There was a problem hiding this 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
( 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 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. - 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. - 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.
There was a problem hiding this comment.
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) = |
There was a problem hiding this comment.
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
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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 () -> |
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
test/slack_payloads.expected
Outdated
@@ -171,6 +171,34 @@ will notify #frontend-bot | |||
] | |||
} | |||
===== file ../mock_payloads/issue_comment.edited.json ===== | |||
will update msg in #some channel | |||
{ | |||
"channel": "some channel", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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
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? |
ef5e936
to
0bfc75d
Compare
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? *) |
There was a problem hiding this comment.
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?
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! |
Just tested, and bot can edit their own message after the workspace editing time passed. Thanks for the catch! |
what's the status on this one? |
@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. |
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:
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
References