@@ -10,10 +10,10 @@ use crate::db::review_prefs::{
1010 upsert_repo_review_prefs, upsert_team_review_prefs, upsert_user_review_prefs,
1111} ;
1212use crate :: db:: users:: DbUser ;
13- use crate :: github;
1413use crate :: github:: queries:: user_comments_in_org:: UserComment ;
1514use crate :: github:: queries:: user_prs:: PullRequestState ;
1615use crate :: github:: queries:: user_prs:: UserPullRequest ;
16+ use crate :: github:: { self , Repository } ;
1717use crate :: handlers:: Context ;
1818use crate :: handlers:: docs_update:: docs_update;
1919use crate :: handlers:: pr_tracking:: { ReviewerWorkqueue , get_assigned_prs} ;
@@ -23,8 +23,8 @@ use crate::utils::pluralize;
2323use crate :: zulip:: api:: { MessageApiResponse , Recipient } ;
2424use crate :: zulip:: client:: ZulipClient ;
2525use crate :: zulip:: commands:: {
26- BackportChannelArgs , BackportVerbArgs , ChatCommand , LookupCmd , PingGoalsArgs , StreamCommand ,
27- WorkqueueCmd , WorkqueueLimit , parse_cli,
26+ AssignPrioArgs , BackportChannelArgs , BackportVerbArgs , ChatCommand , IssuePrio , LookupCmd ,
27+ PingGoalsArgs , StreamCommand , WorkqueueCmd , WorkqueueLimit , parse_cli,
2828} ;
2929use anyhow:: { Context as _, format_err} ;
3030use axum:: Json ;
@@ -377,6 +377,9 @@ async fn handle_command<'a>(
377377 } => user_info_cmd ( & ctx, gh_id, & username, & organization)
378378 . await
379379 . map ( Some ) ,
380+ StreamCommand :: AssignPriority ( args) => {
381+ assign_issue_prio ( ctx, message_data, & args) . await
382+ }
380383 } ;
381384 }
382385
@@ -424,18 +427,8 @@ async fn accept_decline_backport(
424427 ) ) ) ;
425428 }
426429
427- // TODO: factor out the Zulip "URL encoder" to make it practical to use
428- let zulip_send_req = crate :: zulip:: MessageApiRequest {
429- recipient : Recipient :: Stream {
430- id : stream_id,
431- topic : & subject,
432- } ,
433- content : "" ,
434- } ;
435-
436- // NOTE: the Zulip Message API cannot yet pin exactly a single message so the link in the GitHub comment will be to the whole topic
437- // See: https://rust-lang.zulipchat.com/#narrow/channel/122653-zulip/topic/.22near.22.20parameter.20in.20payload.20of.20send.20message.20API
438- let zulip_link = zulip_send_req. url ( zulip_client) ;
430+ let zulip_link =
431+ crate :: zulip:: MessageApiRequest :: new ( stream_id, & subject, "" ) . url ( zulip_client) ;
439432
440433 let ( message_body, approve_backport) = match args. verb {
441434 BackportVerbArgs :: Accept
@@ -488,6 +481,99 @@ async fn accept_decline_backport(
488481 Ok ( None )
489482}
490483
484+ async fn assign_issue_prio (
485+ ctx : Arc < Context > ,
486+ message_data : & Message ,
487+ args_data : & AssignPrioArgs ,
488+ ) -> anyhow:: Result < Option < String > > {
489+ let message = message_data. clone ( ) ;
490+ let args = args_data. clone ( ) ;
491+ let stream_id = message. stream_id . unwrap ( ) ;
492+ let subject = message. subject . unwrap ( ) ;
493+ let zulip_client = & ctx. zulip ;
494+
495+ // Repository owner and name are hardcoded
496+ // This command is only used in this repository
497+ let repo_owner = std:: env:: var ( "MAIN_GH_REPO_OWNER" ) . unwrap_or ( "rust-lang" . to_string ( ) ) ;
498+ let repo_name = std:: env:: var ( "MAIN_GH_REPO_NAME" ) . unwrap_or ( "rust" . to_string ( ) ) ;
499+
500+ let repository = Repository {
501+ full_name : format ! ( "{}/{}" , repo_owner, repo_name) ,
502+ default_branch : "main" . to_string ( ) ,
503+ fork : false ,
504+ parent : None ,
505+ } ;
506+
507+ // Ensure this is an issue and not a pull request
508+ let issue = repository
509+ . get_issue ( & ctx. github , args. issue_num )
510+ . await
511+ . context ( format ! ( "Could not retrieve #{}" , args. issue_num) ) ?;
512+ if issue. pull_request . is_some ( ) {
513+ return Ok ( Some ( format ! (
514+ "Error: #{} is a pull request (must be an issue)" ,
515+ args. issue_num
516+ ) ) ) ;
517+ }
518+
519+ let zulip_link =
520+ crate :: zulip:: MessageApiRequest :: new ( stream_id, & subject, "" ) . url ( zulip_client) ;
521+
522+ // Remove I-prioritize and all P-* labels (if any)
523+ issue
524+ . remove_labels (
525+ & ctx. github ,
526+ vec ! [
527+ github:: Label {
528+ name: "I-prioritize" . to_string( ) ,
529+ } ,
530+ github:: Label {
531+ name: "P-low" . to_string( ) ,
532+ } ,
533+ github:: Label {
534+ name: "P-medium" . to_string( ) ,
535+ } ,
536+ github:: Label {
537+ name: "P-high" . to_string( ) ,
538+ } ,
539+ github:: Label {
540+ name: "P-critical" . to_string( ) ,
541+ } ,
542+ ] ,
543+ )
544+ . await
545+ . context ( "failed to remove labels from the issue" ) ?;
546+
547+ // if just removing priority, nothing else to do
548+ if args. prio == IssuePrio :: None {
549+ return Ok ( None ) ;
550+ }
551+
552+ // post a comment on GitHub
553+ let message_body = format ! (
554+ "Assigning P-{} (discussion on [Zulip]({zulip_link}))." ,
555+ args. prio
556+ ) ;
557+
558+ issue
559+ . post_comment ( & ctx. github , & message_body)
560+ . await
561+ . with_context ( || anyhow:: anyhow!( "Unable to post comment on #{}" , args. issue_num) ) ?;
562+
563+ // Add the specified priority label
564+ issue
565+ . add_labels (
566+ & ctx. github ,
567+ vec ! [ github:: Label {
568+ name: format!( "P-{}" , args. prio) ,
569+ } ] ,
570+ )
571+ . await
572+ . context ( format ! ( "failed to add labels to issue #{}" , args. issue_num) ) ?;
573+
574+ Ok ( None )
575+ }
576+
491577async fn ping_goals_cmd (
492578 ctx : Arc < Context > ,
493579 gh_id : u64 ,
@@ -1358,11 +1444,25 @@ async fn lookup_zulip_username(ctx: &Context, gh_username: &str) -> anyhow::Resu
13581444
13591445#[ derive( serde:: Serialize ) ]
13601446pub ( crate ) struct MessageApiRequest < ' a > {
1447+ /// The recipient of the message. Could be DM or a Stream
13611448 pub ( crate ) recipient : Recipient < ' a > ,
1449+ /// The content of the message
13621450 pub ( crate ) content : & ' a str ,
13631451}
13641452
1365- impl MessageApiRequest < ' _ > {
1453+ impl < ' a > MessageApiRequest < ' _ > {
1454+ pub fn new ( stream_id : u64 , subject : & ' a str , content : & ' a str ) -> MessageApiRequest < ' a > {
1455+ MessageApiRequest {
1456+ recipient : Recipient :: Stream {
1457+ id : stream_id,
1458+ topic : subject,
1459+ } ,
1460+ content,
1461+ }
1462+ }
1463+
1464+ // note: the Zulip Message API cannot yet pin exactly a single message so the link in the GitHub comment will be to the whole topic
1465+ // See: https://rust-lang.zulipchat.com/#narrow/channel/122653-zulip/topic/.22near.22.20parameter.20in.20payload.20of.20send.20message.20API
13661466 pub fn url ( & self , zulip : & ZulipClient ) -> String {
13671467 self . recipient . url ( zulip)
13681468 }
0 commit comments