github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/pr/shared/editable_http.go (about)

     1  package shared
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"github.com/ungtb10d/cli/v2/api"
     7  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
     8  	"github.com/shurcooL/githubv4"
     9  	"golang.org/x/sync/errgroup"
    10  )
    11  
    12  func UpdateIssue(httpClient *http.Client, repo ghrepo.Interface, id string, isPR bool, options Editable) error {
    13  	var wg errgroup.Group
    14  
    15  	// Labels are updated through discrete mutations to avoid having to replace the entire list of labels
    16  	// and risking race conditions.
    17  	if options.Labels.Edited {
    18  		if len(options.Labels.Add) > 0 {
    19  			wg.Go(func() error {
    20  				addedLabelIds, err := options.Metadata.LabelsToIDs(options.Labels.Add)
    21  				if err != nil {
    22  					return err
    23  				}
    24  				return addLabels(httpClient, id, repo, addedLabelIds)
    25  			})
    26  		}
    27  		if len(options.Labels.Remove) > 0 {
    28  			wg.Go(func() error {
    29  				removeLabelIds, err := options.Metadata.LabelsToIDs(options.Labels.Remove)
    30  				if err != nil {
    31  					return err
    32  				}
    33  				return removeLabels(httpClient, id, repo, removeLabelIds)
    34  			})
    35  		}
    36  	}
    37  
    38  	if dirtyExcludingLabels(options) {
    39  		wg.Go(func() error {
    40  			return replaceIssueFields(httpClient, repo, id, isPR, options)
    41  		})
    42  	}
    43  
    44  	return wg.Wait()
    45  }
    46  
    47  func replaceIssueFields(httpClient *http.Client, repo ghrepo.Interface, id string, isPR bool, options Editable) error {
    48  	apiClient := api.NewClientFromHTTP(httpClient)
    49  	assigneeIds, err := options.AssigneeIds(apiClient, repo)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	projectIds, err := options.ProjectIds()
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	milestoneId, err := options.MilestoneId()
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	if isPR {
    65  		params := githubv4.UpdatePullRequestInput{
    66  			PullRequestID: id,
    67  			Title:         ghString(options.TitleValue()),
    68  			Body:          ghString(options.BodyValue()),
    69  			AssigneeIDs:   ghIds(assigneeIds),
    70  			ProjectIDs:    ghIds(projectIds),
    71  			MilestoneID:   ghId(milestoneId),
    72  		}
    73  		if options.Base.Edited {
    74  			params.BaseRefName = ghString(&options.Base.Value)
    75  		}
    76  		return updatePullRequest(httpClient, repo, params)
    77  	}
    78  
    79  	params := githubv4.UpdateIssueInput{
    80  		ID:          id,
    81  		Title:       ghString(options.TitleValue()),
    82  		Body:        ghString(options.BodyValue()),
    83  		AssigneeIDs: ghIds(assigneeIds),
    84  		ProjectIDs:  ghIds(projectIds),
    85  		MilestoneID: ghId(milestoneId),
    86  	}
    87  	return updateIssue(httpClient, repo, params)
    88  }
    89  
    90  func dirtyExcludingLabels(e Editable) bool {
    91  	return e.Title.Edited ||
    92  		e.Body.Edited ||
    93  		e.Base.Edited ||
    94  		e.Reviewers.Edited ||
    95  		e.Assignees.Edited ||
    96  		e.Projects.Edited ||
    97  		e.Milestone.Edited
    98  }
    99  
   100  func addLabels(httpClient *http.Client, id string, repo ghrepo.Interface, labels []string) error {
   101  	params := githubv4.AddLabelsToLabelableInput{
   102  		LabelableID: id,
   103  		LabelIDs:    *ghIds(&labels),
   104  	}
   105  
   106  	var mutation struct {
   107  		AddLabelsToLabelable struct {
   108  			Typename string `graphql:"__typename"`
   109  		} `graphql:"addLabelsToLabelable(input: $input)"`
   110  	}
   111  
   112  	variables := map[string]interface{}{"input": params}
   113  	gql := api.NewClientFromHTTP(httpClient)
   114  	return gql.Mutate(repo.RepoHost(), "LabelAdd", &mutation, variables)
   115  }
   116  
   117  func removeLabels(httpClient *http.Client, id string, repo ghrepo.Interface, labels []string) error {
   118  	params := githubv4.RemoveLabelsFromLabelableInput{
   119  		LabelableID: id,
   120  		LabelIDs:    *ghIds(&labels),
   121  	}
   122  
   123  	var mutation struct {
   124  		RemoveLabelsFromLabelable struct {
   125  			Typename string `graphql:"__typename"`
   126  		} `graphql:"removeLabelsFromLabelable(input: $input)"`
   127  	}
   128  
   129  	variables := map[string]interface{}{"input": params}
   130  	gql := api.NewClientFromHTTP(httpClient)
   131  	return gql.Mutate(repo.RepoHost(), "LabelRemove", &mutation, variables)
   132  }
   133  
   134  func updateIssue(httpClient *http.Client, repo ghrepo.Interface, params githubv4.UpdateIssueInput) error {
   135  	var mutation struct {
   136  		UpdateIssue struct {
   137  			Typename string `graphql:"__typename"`
   138  		} `graphql:"updateIssue(input: $input)"`
   139  	}
   140  	variables := map[string]interface{}{"input": params}
   141  	gql := api.NewClientFromHTTP(httpClient)
   142  	return gql.Mutate(repo.RepoHost(), "IssueUpdate", &mutation, variables)
   143  }
   144  
   145  func updatePullRequest(httpClient *http.Client, repo ghrepo.Interface, params githubv4.UpdatePullRequestInput) error {
   146  	var mutation struct {
   147  		UpdatePullRequest struct {
   148  			Typename string `graphql:"__typename"`
   149  		} `graphql:"updatePullRequest(input: $input)"`
   150  	}
   151  	variables := map[string]interface{}{"input": params}
   152  	gql := api.NewClientFromHTTP(httpClient)
   153  	err := gql.Mutate(repo.RepoHost(), "PullRequestUpdate", &mutation, variables)
   154  	return err
   155  }
   156  
   157  func ghIds(s *[]string) *[]githubv4.ID {
   158  	if s == nil {
   159  		return nil
   160  	}
   161  	ids := make([]githubv4.ID, len(*s))
   162  	for i, v := range *s {
   163  		ids[i] = v
   164  	}
   165  	return &ids
   166  }
   167  
   168  func ghId(s *string) *githubv4.ID {
   169  	if s == nil {
   170  		return nil
   171  	}
   172  	if *s == "" {
   173  		r := githubv4.ID(nil)
   174  		return &r
   175  	}
   176  	r := githubv4.ID(*s)
   177  	return &r
   178  }
   179  
   180  func ghString(s *string) *githubv4.String {
   181  	if s == nil {
   182  		return nil
   183  	}
   184  	r := githubv4.String(*s)
   185  	return &r
   186  }