@@ -622,6 +622,191 @@ func Test_UpdatePullRequest_Draft(t *testing.T) {
622622 }
623623}
624624
625+ func Test_UpdatePullRequest_Draft (t * testing.T ) {
626+ // Setup mock PR for success case
627+ mockUpdatedPR := & github.PullRequest {
628+ Number : github .Ptr (42 ),
629+ Title : github .Ptr ("Test PR Title" ),
630+ State : github .Ptr ("open" ),
631+ HTMLURL : github .Ptr ("https://github.com/owner/repo/pull/42" ),
632+ Body : github .Ptr ("Test PR body." ),
633+ MaintainerCanModify : github .Ptr (false ),
634+ Draft : github .Ptr (false ), // Updated to ready for review
635+ Base : & github.PullRequestBranch {
636+ Ref : github .Ptr ("main" ),
637+ },
638+ }
639+
640+ tests := []struct {
641+ name string
642+ mockedClient * http.Client
643+ requestArgs map [string ]interface {}
644+ expectError bool
645+ expectedPR * github.PullRequest
646+ expectedErrMsg string
647+ }{
648+ {
649+ name : "successful draft update to ready for review" ,
650+ mockedClient : githubv4mock .NewMockedHTTPClient (
651+ githubv4mock .NewQueryMatcher (
652+ struct {
653+ Repository struct {
654+ PullRequest struct {
655+ ID githubv4.ID
656+ IsDraft githubv4.Boolean
657+ } `graphql:"pullRequest(number: $prNum)"`
658+ } `graphql:"repository(owner: $owner, name: $repo)"`
659+ }{},
660+ map [string ]any {
661+ "owner" : githubv4 .String ("owner" ),
662+ "repo" : githubv4 .String ("repo" ),
663+ "prNum" : githubv4 .Int (42 ),
664+ },
665+ githubv4mock .DataResponse (map [string ]any {
666+ "repository" : map [string ]any {
667+ "pullRequest" : map [string ]any {
668+ "id" : "PR_kwDOA0xdyM50BPaO" ,
669+ "isDraft" : true , // Current state is draft
670+ },
671+ },
672+ }),
673+ ),
674+ githubv4mock .NewMutationMatcher (
675+ struct {
676+ MarkPullRequestReadyForReview struct {
677+ PullRequest struct {
678+ ID githubv4.ID
679+ IsDraft githubv4.Boolean
680+ }
681+ } `graphql:"markPullRequestReadyForReview(input: $input)"`
682+ }{},
683+ githubv4.MarkPullRequestReadyForReviewInput {
684+ PullRequestID : "PR_kwDOA0xdyM50BPaO" ,
685+ },
686+ nil ,
687+ githubv4mock .DataResponse (map [string ]any {
688+ "markPullRequestReadyForReview" : map [string ]any {
689+ "pullRequest" : map [string ]any {
690+ "id" : "PR_kwDOA0xdyM50BPaO" ,
691+ "isDraft" : false ,
692+ },
693+ },
694+ }),
695+ ),
696+ ),
697+ requestArgs : map [string ]interface {}{
698+ "owner" : "owner" ,
699+ "repo" : "repo" ,
700+ "pullNumber" : float64 (42 ),
701+ "draft" : false ,
702+ },
703+ expectError : false ,
704+ expectedPR : mockUpdatedPR ,
705+ },
706+ {
707+ name : "successful convert pull request to draft" ,
708+ mockedClient : githubv4mock .NewMockedHTTPClient (
709+ githubv4mock .NewQueryMatcher (
710+ struct {
711+ Repository struct {
712+ PullRequest struct {
713+ ID githubv4.ID
714+ IsDraft githubv4.Boolean
715+ } `graphql:"pullRequest(number: $prNum)"`
716+ } `graphql:"repository(owner: $owner, name: $repo)"`
717+ }{},
718+ map [string ]any {
719+ "owner" : githubv4 .String ("owner" ),
720+ "repo" : githubv4 .String ("repo" ),
721+ "prNum" : githubv4 .Int (42 ),
722+ },
723+ githubv4mock .DataResponse (map [string ]any {
724+ "repository" : map [string ]any {
725+ "pullRequest" : map [string ]any {
726+ "id" : "PR_kwDOA0xdyM50BPaO" ,
727+ "isDraft" : false , // Current state is draft
728+ },
729+ },
730+ }),
731+ ),
732+ githubv4mock .NewMutationMatcher (
733+ struct {
734+ ConvertPullRequestToDraft struct {
735+ PullRequest struct {
736+ ID githubv4.ID
737+ IsDraft githubv4.Boolean
738+ }
739+ } `graphql:"convertPullRequestToDraft(input: $input)"`
740+ }{},
741+ githubv4.ConvertPullRequestToDraftInput {
742+ PullRequestID : "PR_kwDOA0xdyM50BPaO" ,
743+ },
744+ nil ,
745+ githubv4mock .DataResponse (map [string ]any {
746+ "convertPullRequestToDraft" : map [string ]any {
747+ "pullRequest" : map [string ]any {
748+ "id" : "PR_kwDOA0xdyM50BPaO" ,
749+ "isDraft" : true ,
750+ },
751+ },
752+ }),
753+ ),
754+ ),
755+ requestArgs : map [string ]interface {}{
756+ "owner" : "owner" ,
757+ "repo" : "repo" ,
758+ "pullNumber" : float64 (42 ),
759+ "draft" : true ,
760+ },
761+ expectError : false ,
762+ expectedPR : mockUpdatedPR ,
763+ },
764+ }
765+
766+ for _ , tc := range tests {
767+ t .Run (tc .name , func (t * testing.T ) {
768+ // For draft-only tests, we need to mock both GraphQL and the final REST GET call
769+ restClient := github .NewClient (mock .NewMockedHTTPClient (
770+ mock .WithRequestMatch (
771+ mock .GetReposPullsByOwnerByRepoByPullNumber ,
772+ mockUpdatedPR ,
773+ ),
774+ ))
775+ gqlClient := githubv4 .NewClient (tc .mockedClient )
776+
777+ _ , handler := UpdatePullRequest (stubGetClientFn (restClient ), stubGetGQLClientFn (gqlClient ), translations .NullTranslationHelper )
778+
779+ request := createMCPRequest (tc .requestArgs )
780+
781+ result , err := handler (context .Background (), request )
782+
783+ if tc .expectError || tc .expectedErrMsg != "" {
784+ require .NoError (t , err )
785+ require .True (t , result .IsError )
786+ errorContent := getErrorResult (t , result )
787+ if tc .expectedErrMsg != "" {
788+ assert .Contains (t , errorContent .Text , tc .expectedErrMsg )
789+ }
790+ return
791+ }
792+
793+ require .NoError (t , err )
794+ require .False (t , result .IsError )
795+
796+ textContent := getTextResult (t , result )
797+
798+ // Unmarshal and verify the successful result
799+ var returnedPR github.PullRequest
800+ err = json .Unmarshal ([]byte (textContent .Text ), & returnedPR )
801+ require .NoError (t , err )
802+ assert .Equal (t , * tc .expectedPR .Number , * returnedPR .Number )
803+ if tc .expectedPR .Draft != nil {
804+ assert .Equal (t , * tc .expectedPR .Draft , * returnedPR .Draft )
805+ }
806+ })
807+ }
808+ }
809+
625810func Test_ListPullRequests (t * testing.T ) {
626811 // Verify tool definition once
627812 mockClient := github .NewClient (nil )
0 commit comments