1
1
use anyhow:: Context ;
2
2
use chrono:: { DateTime , Utc } ;
3
3
use http:: header:: USER_AGENT ;
4
+ use serde:: de:: DeserializeOwned ;
4
5
5
6
use crate :: { api:: github:: Issue , load:: SiteCtxt } ;
6
7
@@ -226,6 +227,124 @@ impl Client {
226
227
}
227
228
}
228
229
230
+ pub async fn get_comments ( & self , pull_request : u32 ) -> anyhow:: Result < Vec < ResponseComment > > {
231
+ const QUERY : & str = "query($owner: String!, $repo: String!, $pr: Int!, $cursor: String) {
232
+ repository(owner: $owner, name: $repo) {
233
+ pullRequest(number: $pr) {
234
+ comments(first: 100, after: $cursor) {
235
+ nodes {
236
+ id
237
+ body
238
+ isMinimized
239
+ viewerDidAuthor
240
+ }
241
+ pageInfo {
242
+ endCursor
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }" ;
248
+
249
+ #[ derive( Debug , serde:: Deserialize ) ]
250
+ struct Response {
251
+ repository : ResponseRepo ,
252
+ }
253
+ #[ derive( Debug , serde:: Deserialize ) ]
254
+ #[ serde( rename_all = "camelCase" ) ]
255
+ struct ResponseRepo {
256
+ pull_request : ResponsePR ,
257
+ }
258
+ #[ derive( Debug , serde:: Deserialize ) ]
259
+ struct ResponsePR {
260
+ comments : ResponseComments ,
261
+ }
262
+ #[ derive( Debug , serde:: Deserialize ) ]
263
+ #[ serde( rename_all = "camelCase" ) ]
264
+ struct ResponseComments {
265
+ nodes : Vec < ResponseComment > ,
266
+ page_info : GraphPageInfo ,
267
+ }
268
+
269
+ let owner = "rust-lang" ;
270
+ let repo = "rust" ;
271
+
272
+ let mut comments = Vec :: new ( ) ;
273
+ let mut cursor = None ;
274
+ loop {
275
+ let mut resp: Response = self
276
+ . graphql (
277
+ QUERY ,
278
+ serde_json:: json!( {
279
+ "owner" : owner,
280
+ "repo" : repo,
281
+ "pr" : pull_request,
282
+ "cursor" : cursor,
283
+ } ) ,
284
+ )
285
+ . await ?;
286
+ cursor = resp. repository . pull_request . comments . page_info . end_cursor ;
287
+ comments. append ( & mut resp. repository . pull_request . comments . nodes ) ;
288
+
289
+ if cursor. is_none ( ) {
290
+ break ;
291
+ }
292
+ }
293
+ Ok ( comments)
294
+ }
295
+
296
+ pub async fn hide_comment ( & self , comment_id : & str , reason : & str ) -> anyhow:: Result < ( ) > {
297
+ #[ derive( serde:: Deserialize ) ]
298
+ struct MinimizeData { }
299
+
300
+ const MINIMIZE : & str = "mutation($node_id: ID!, $reason: ReportedContentClassifiers!) {
301
+ minimizeComment(input: {subjectId: $node_id, classifier: $reason}) {
302
+ __typename
303
+ }
304
+ }" ;
305
+
306
+ self . graphql :: < Option < MinimizeData > , _ > (
307
+ MINIMIZE ,
308
+ serde_json:: json!( {
309
+ "node_id" : comment_id,
310
+ "reason" : reason,
311
+ } ) ,
312
+ )
313
+ . await ?;
314
+ Ok ( ( ) )
315
+ }
316
+
317
+ async fn graphql < T : DeserializeOwned , V : serde:: Serialize > (
318
+ & self ,
319
+ query : & str ,
320
+ variables : V ,
321
+ ) -> anyhow:: Result < T > {
322
+ #[ derive( serde:: Serialize ) ]
323
+ struct GraphPayload < ' a , V > {
324
+ query : & ' a str ,
325
+ variables : V ,
326
+ }
327
+
328
+ let response: GraphResponse < T > = self
329
+ . inner
330
+ . post ( & self . repository_url )
331
+ . json ( & GraphPayload { query, variables } )
332
+ . send ( )
333
+ . await ?
334
+ . error_for_status ( ) ?
335
+ . json ( )
336
+ . await ?;
337
+
338
+ if response. errors . is_empty ( ) {
339
+ Ok ( response. data )
340
+ } else {
341
+ Err ( anyhow:: anyhow!(
342
+ "GraphQL query failed: {}" ,
343
+ response. errors[ 0 ] . message
344
+ ) )
345
+ }
346
+ }
347
+
229
348
async fn send (
230
349
& self ,
231
350
request : reqwest:: RequestBuilder ,
@@ -238,6 +357,33 @@ impl Client {
238
357
}
239
358
}
240
359
360
+ #[ derive( serde:: Deserialize ) ]
361
+ struct GraphResponse < T > {
362
+ data : T ,
363
+ #[ serde( default ) ]
364
+ errors : Vec < GraphError > ,
365
+ }
366
+
367
+ #[ derive( Debug , serde:: Deserialize ) ]
368
+ struct GraphError {
369
+ message : String ,
370
+ }
371
+
372
+ #[ derive( Debug , serde:: Deserialize ) ]
373
+ #[ serde( rename_all = "camelCase" ) ]
374
+ struct GraphPageInfo {
375
+ end_cursor : Option < String > ,
376
+ }
377
+
378
+ #[ derive( Debug , serde:: Deserialize ) ]
379
+ #[ serde( rename_all = "camelCase" ) ]
380
+ pub struct ResponseComment {
381
+ pub id : String ,
382
+ pub body : String ,
383
+ pub is_minimized : bool ,
384
+ pub viewer_did_author : bool ,
385
+ }
386
+
241
387
#[ derive( Debug , serde:: Deserialize ) ]
242
388
pub struct CreatePrResponse {
243
389
pub number : u32 ,
0 commit comments