github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/issue/transfer/transfer.go (about)

     1  package transfer
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"github.com/ungtb10d/cli/v2/api"
     8  	"github.com/ungtb10d/cli/v2/internal/config"
     9  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    10  	"github.com/ungtb10d/cli/v2/pkg/cmd/issue/shared"
    11  	"github.com/ungtb10d/cli/v2/pkg/cmdutil"
    12  	"github.com/ungtb10d/cli/v2/pkg/iostreams"
    13  	"github.com/shurcooL/githubv4"
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  type TransferOptions struct {
    18  	HttpClient func() (*http.Client, error)
    19  	Config     func() (config.Config, error)
    20  	IO         *iostreams.IOStreams
    21  	BaseRepo   func() (ghrepo.Interface, error)
    22  
    23  	IssueSelector    string
    24  	DestRepoSelector string
    25  }
    26  
    27  func NewCmdTransfer(f *cmdutil.Factory, runF func(*TransferOptions) error) *cobra.Command {
    28  	opts := TransferOptions{
    29  		IO:         f.IOStreams,
    30  		HttpClient: f.HttpClient,
    31  		Config:     f.Config,
    32  	}
    33  
    34  	cmd := &cobra.Command{
    35  		Use:   "transfer {<number> | <url>} <destination-repo>",
    36  		Short: "Transfer issue to another repository",
    37  		Args:  cmdutil.ExactArgs(2, "issue and destination repository are required"),
    38  		RunE: func(cmd *cobra.Command, args []string) error {
    39  			opts.BaseRepo = f.BaseRepo
    40  			opts.IssueSelector = args[0]
    41  			opts.DestRepoSelector = args[1]
    42  
    43  			if runF != nil {
    44  				return runF(&opts)
    45  			}
    46  
    47  			return transferRun(&opts)
    48  		},
    49  	}
    50  
    51  	return cmd
    52  }
    53  
    54  func transferRun(opts *TransferOptions) error {
    55  	httpClient, err := opts.HttpClient()
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	issue, baseRepo, err := shared.IssueFromArgWithFields(httpClient, opts.BaseRepo, opts.IssueSelector, []string{"id", "number"})
    61  	if err != nil {
    62  		return err
    63  	}
    64  	if issue.IsPullRequest() {
    65  		return fmt.Errorf("issue #%d is a pull request and cannot be transferred", issue.Number)
    66  	}
    67  
    68  	destRepo, err := ghrepo.FromFullNameWithHost(opts.DestRepoSelector, baseRepo.RepoHost())
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	url, err := issueTransfer(httpClient, issue.ID, destRepo)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	_, err = fmt.Fprintln(opts.IO.Out, url)
    79  	return err
    80  }
    81  
    82  func issueTransfer(httpClient *http.Client, issueID string, destRepo ghrepo.Interface) (string, error) {
    83  	var destinationRepoID string
    84  	if r, ok := destRepo.(*api.Repository); ok {
    85  		destinationRepoID = r.ID
    86  	} else {
    87  		apiClient := api.NewClientFromHTTP(httpClient)
    88  		r, err := api.GitHubRepo(apiClient, destRepo)
    89  		if err != nil {
    90  			return "", err
    91  		}
    92  		destinationRepoID = r.ID
    93  	}
    94  
    95  	var mutation struct {
    96  		TransferIssue struct {
    97  			Issue struct {
    98  				URL string
    99  			}
   100  		} `graphql:"transferIssue(input: $input)"`
   101  	}
   102  
   103  	variables := map[string]interface{}{
   104  		"input": githubv4.TransferIssueInput{
   105  			IssueID:      issueID,
   106  			RepositoryID: destinationRepoID,
   107  		},
   108  	}
   109  
   110  	gql := api.NewClientFromHTTP(httpClient)
   111  	err := gql.Mutate(destRepo.RepoHost(), "IssueTransfer", &mutation, variables)
   112  	return mutation.TransferIssue.Issue.URL, err
   113  }