1
1
use anyhow:: Context as _;
2
2
3
3
use crate :: config:: RangeDiffConfig ;
4
+ use crate :: db:: issue_data:: IssueData ;
5
+ use crate :: github:: CommitBase ;
4
6
use crate :: github:: GithubCompare ;
5
7
use crate :: github:: IssueRepository ;
6
8
use crate :: github:: IssuesEvent ;
9
+ use crate :: github:: ReportedContentClassifiers ;
7
10
use crate :: handlers:: Context ;
8
11
12
+ /// Key for the state in the database
13
+ const RANGE_DIFF_LINK_KEY : & str = "range-diff-link" ;
14
+
15
+ /// State stored in the database
16
+ #[ derive( Debug , Default , serde:: Deserialize , serde:: Serialize , Clone , PartialEq ) ]
17
+ struct RangeDiffLinkState {
18
+ /// ID of the most recent range-diff comment.
19
+ last_comment : Option < String > ,
20
+ }
21
+
9
22
pub ( super ) async fn handle_event (
10
23
ctx : & Context ,
11
24
host : & str ,
@@ -23,25 +36,45 @@ pub(super) async fn handle_event(
23
36
} ;
24
37
25
38
let base = event. issue . base . as_ref ( ) . context ( "no base ref" ) ?;
26
- let org = event. repository . owner ( ) ;
27
- let repo = event. repository . name ( ) ;
39
+ let issue_repo = IssueRepository {
40
+ organization : event. repository . owner ( ) . to_string ( ) ,
41
+ repository : event. repository . name ( ) . to_string ( ) ,
42
+ } ;
28
43
29
44
let compare_before = ctx
30
45
. github
31
- . compare (
32
- & IssueRepository {
33
- organization : org. to_string ( ) ,
34
- repository : repo. to_string ( ) ,
35
- } ,
36
- & base. sha ,
37
- & before,
38
- )
46
+ . compare ( & issue_repo, & base. sha , & before)
39
47
. await
40
48
. context ( "failed to get the before compare" ) ?;
41
49
50
+ if let Some ( message) = changed_base_commit (
51
+ host,
52
+ & issue_repo,
53
+ base,
54
+ & compare_before,
55
+ compare_after,
56
+ before,
57
+ after,
58
+ ) {
59
+ // Rebase detected, post a comment linking to our range-diff.
60
+ post_new_comment ( ctx, event, message) . await ?;
61
+ }
62
+
63
+ Ok ( ( ) )
64
+ }
65
+
66
+ fn changed_base_commit (
67
+ host : & str ,
68
+ issue_repo : & IssueRepository ,
69
+ base : & CommitBase ,
70
+ compare_before : & GithubCompare ,
71
+ compare_after : & GithubCompare ,
72
+ oldhead : & str ,
73
+ newhead : & str ,
74
+ ) -> Option < String > {
42
75
// Does the merge_base_commits differs? No, not a force-push with rebase.
43
76
if compare_before. merge_base_commit . sha == compare_after. merge_base_commit . sha {
44
- return Ok ( ( ) ) ;
77
+ return None ;
45
78
}
46
79
47
80
let protocol = if host. starts_with ( "localhost:" ) {
@@ -51,13 +84,137 @@ pub(super) async fn handle_event(
51
84
} ;
52
85
53
86
let branch = & base. git_ref ;
54
- let ( oldbase, oldhead ) = ( & compare_before. merge_base_commit . sha , before ) ;
55
- let ( newbase, newhead ) = ( & compare_after. merge_base_commit . sha , after ) ;
87
+ let oldbase = & compare_before. merge_base_commit . sha ;
88
+ let newbase = & compare_after. merge_base_commit . sha ;
56
89
57
- // Rebase detected, post a comment to our range-diff.
58
- event. issue . post_comment ( & ctx. github ,
59
- & format ! ( r#"This PR was rebased onto a different {branch} commit! Check out the changes with our [`range-diff`]({protocol}://{host}/gh-range-diff/{org}/{repo}/{oldbase}..{oldhead}/{newbase}..{newhead})."# )
60
- ) . await . context ( "failed to post range-diff comment" ) ?;
90
+ let message = format ! (
91
+ r#"This PR was rebased onto a different {branch} commit. Here's a [range-diff]({protocol}://{host}/gh-range-diff/{issue_repo}/{oldbase}..{oldhead}/{newbase}..{newhead}) highlighting what actually changed.
92
+
93
+ *Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.*"#
94
+ ) ;
95
+
96
+ Some ( message)
97
+ }
98
+
99
+ async fn post_new_comment (
100
+ ctx : & Context ,
101
+ event : & IssuesEvent ,
102
+ message : String ,
103
+ ) -> anyhow:: Result < ( ) > {
104
+ let mut db = ctx. db . get ( ) . await ;
105
+ let mut state: IssueData < ' _ , RangeDiffLinkState > =
106
+ IssueData :: load ( & mut db, & event. issue , RANGE_DIFF_LINK_KEY ) . await ?;
107
+
108
+ // Hide previous range-diff comment.
109
+ if let Some ( last_comment) = state. data . last_comment {
110
+ event
111
+ . issue
112
+ . hide_comment (
113
+ & ctx. github ,
114
+ & last_comment,
115
+ ReportedContentClassifiers :: Outdated ,
116
+ )
117
+ . await
118
+ . context ( "failed to hide previous range-diff comment" ) ?;
119
+ }
120
+
121
+ // Post new range-diff comment and remember it.
122
+ state. data . last_comment = Some (
123
+ event
124
+ . issue
125
+ . post_comment ( & ctx. github , & message)
126
+ . await
127
+ . context ( "failed to post range-diff comment" ) ?
128
+ . node_id ,
129
+ ) ;
130
+
131
+ state. save ( ) . await ?;
61
132
62
133
Ok ( ( ) )
63
134
}
135
+
136
+ #[ cfg( test) ]
137
+ mod tests {
138
+ use crate :: handlers:: check_commits:: dummy_commit_from_body;
139
+
140
+ use super :: changed_base_commit;
141
+
142
+ #[ test]
143
+ fn unchanged_base_commit ( ) {
144
+ assert_eq ! (
145
+ changed_base_commit(
146
+ "mytriagebot.com" ,
147
+ & crate :: github:: IssueRepository {
148
+ organization: "rust-lang" . to_string( ) ,
149
+ repository: "rust" . to_string( )
150
+ } ,
151
+ & crate :: github:: CommitBase {
152
+ sha: "sha-base-commit" . to_string( ) ,
153
+ git_ref: "master" . to_string( ) ,
154
+ repo: None
155
+ } ,
156
+ & crate :: github:: GithubCompare {
157
+ base_commit: dummy_commit_from_body( "base-commit-sha" , "base-commit-body" ) ,
158
+ merge_base_commit: dummy_commit_from_body(
159
+ "same-merge-commit" ,
160
+ "merge-commit-body"
161
+ ) ,
162
+ files: vec![ ]
163
+ } ,
164
+ & crate :: github:: GithubCompare {
165
+ base_commit: dummy_commit_from_body( "base-commit-sha" , "base-commit-body" ) ,
166
+ merge_base_commit: dummy_commit_from_body(
167
+ "same-merge-commit" ,
168
+ "merge-commit-body"
169
+ ) ,
170
+ files: vec![ ]
171
+ } ,
172
+ "oldhead" ,
173
+ "newhead"
174
+ ) ,
175
+ None
176
+ ) ;
177
+ }
178
+
179
+ #[ test]
180
+ fn changed_base_commit_ ( ) {
181
+ assert_eq ! (
182
+ changed_base_commit(
183
+ "mytriagebot.com" ,
184
+ & crate :: github:: IssueRepository {
185
+ organization: "rust-lang" . to_string( ) ,
186
+ repository: "rust" . to_string( )
187
+ } ,
188
+ & crate :: github:: CommitBase {
189
+ sha: "sha-base-commit" . to_string( ) ,
190
+ git_ref: "master" . to_string( ) ,
191
+ repo: None
192
+ } ,
193
+ & crate :: github:: GithubCompare {
194
+ base_commit: dummy_commit_from_body( "base-commit-sha" , "base-commit-body" ) ,
195
+ merge_base_commit: dummy_commit_from_body(
196
+ "before-merge-commit" ,
197
+ "merge-commit-body"
198
+ ) ,
199
+ files: vec![ ]
200
+ } ,
201
+ & crate :: github:: GithubCompare {
202
+ base_commit: dummy_commit_from_body( "base-commit-sha" , "base-commit-body" ) ,
203
+ merge_base_commit: dummy_commit_from_body(
204
+ "after-merge-commit" ,
205
+ "merge-commit-body"
206
+ ) ,
207
+ files: vec![ ]
208
+ } ,
209
+ "oldhead" ,
210
+ "newhead"
211
+ ) ,
212
+ Some (
213
+ r#"This PR was rebased onto a different master commit. Here's a [range-diff](https://mytriagebot.com/gh-range-diff/rust-lang/rust/before-merge-commit..oldhead/after-merge-commit..newhead) highlighting what actually changed.
214
+
215
+ *Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.*"#
216
+ . to_string( )
217
+ )
218
+ ) ;
219
+ }
220
+ }
0 commit comments