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

     1  package label
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"strings"
     7  
     8  	"github.com/ungtb10d/cli/v2/api"
     9  	"github.com/ungtb10d/cli/v2/internal/ghrepo"
    10  )
    11  
    12  const (
    13  	maxPageSize = 100
    14  
    15  	defaultOrder = "asc"
    16  	defaultSort  = "created"
    17  )
    18  
    19  var defaultFields = []string{
    20  	"color",
    21  	"description",
    22  	"name",
    23  }
    24  
    25  type listLabelsResponseData struct {
    26  	Repository struct {
    27  		Labels struct {
    28  			TotalCount int
    29  			Nodes      []label
    30  			PageInfo   struct {
    31  				HasNextPage bool
    32  				EndCursor   string
    33  			}
    34  		}
    35  	}
    36  }
    37  
    38  type listQueryOptions struct {
    39  	Limit int
    40  	Query string
    41  	Order string
    42  	Sort  string
    43  
    44  	fields []string
    45  }
    46  
    47  func (opts listQueryOptions) OrderBy() map[string]string {
    48  	// Set on copy to keep original intact.
    49  	if opts.Order == "" {
    50  		opts.Order = defaultOrder
    51  	}
    52  	if opts.Sort == "" {
    53  		opts.Sort = defaultSort
    54  	}
    55  
    56  	field := strings.ToUpper(opts.Sort)
    57  	if opts.Sort == "created" {
    58  		field = "CREATED_AT"
    59  	}
    60  	return map[string]string{
    61  		"direction": strings.ToUpper(opts.Order),
    62  		"field":     field,
    63  	}
    64  }
    65  
    66  // listLabels lists the labels in the given repo. Pass -1 for limit to list all labels;
    67  // otherwise, only that number of labels is returned for any number of pages.
    68  func listLabels(client *http.Client, repo ghrepo.Interface, opts listQueryOptions) ([]label, int, error) {
    69  	if len(opts.fields) == 0 {
    70  		opts.fields = defaultFields
    71  	}
    72  
    73  	apiClient := api.NewClientFromHTTP(client)
    74  	fragment := fmt.Sprintf("fragment label on Label{%s}", strings.Join(opts.fields, ","))
    75  	query := fragment + `
    76  	query LabelList($owner: String!, $repo: String!, $limit: Int!, $endCursor: String, $query: String, $orderBy: LabelOrder) {
    77  		repository(owner: $owner, name: $repo) {
    78  			labels(first: $limit, after: $endCursor, query: $query, orderBy: $orderBy) {
    79  				totalCount,
    80  				nodes {
    81  					...label
    82  				}
    83  				pageInfo {
    84  					hasNextPage
    85  					endCursor
    86  				}
    87  			}
    88  		}
    89  	}`
    90  
    91  	variables := map[string]interface{}{
    92  		"owner":   repo.RepoOwner(),
    93  		"repo":    repo.RepoName(),
    94  		"orderBy": opts.OrderBy(),
    95  		"query":   opts.Query,
    96  	}
    97  
    98  	var labels []label
    99  	var totalCount int
   100  
   101  loop:
   102  	for {
   103  		var response listLabelsResponseData
   104  		variables["limit"] = determinePageSize(opts.Limit - len(labels))
   105  		err := apiClient.GraphQL(repo.RepoHost(), query, variables, &response)
   106  		if err != nil {
   107  			return nil, 0, err
   108  		}
   109  
   110  		totalCount = response.Repository.Labels.TotalCount
   111  
   112  		for _, label := range response.Repository.Labels.Nodes {
   113  			labels = append(labels, label)
   114  			if len(labels) == opts.Limit {
   115  				break loop
   116  			}
   117  		}
   118  
   119  		if response.Repository.Labels.PageInfo.HasNextPage {
   120  			variables["endCursor"] = response.Repository.Labels.PageInfo.EndCursor
   121  		} else {
   122  			break
   123  		}
   124  	}
   125  
   126  	return labels, totalCount, nil
   127  }
   128  
   129  func determinePageSize(numRequestedItems int) int {
   130  	// If numRequestedItems is -1 then retrieve maxPageSize
   131  	if numRequestedItems < 0 || numRequestedItems > maxPageSize {
   132  		return maxPageSize
   133  	}
   134  	return numRequestedItems
   135  }