github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/internal/featuredetection/feature_detection.go (about)

     1  package featuredetection
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"github.com/ungtb10d/cli/v2/api"
     7  	"github.com/ungtb10d/cli/v2/internal/ghinstance"
     8  )
     9  
    10  type Detector interface {
    11  	IssueFeatures() (IssueFeatures, error)
    12  	PullRequestFeatures() (PullRequestFeatures, error)
    13  	RepositoryFeatures() (RepositoryFeatures, error)
    14  }
    15  
    16  type IssueFeatures struct {
    17  	StateReason bool
    18  }
    19  
    20  var allIssueFeatures = IssueFeatures{
    21  	StateReason: true,
    22  }
    23  
    24  type PullRequestFeatures struct {
    25  	ReviewDecision       bool
    26  	StatusCheckRollup    bool
    27  	BranchProtectionRule bool
    28  	MergeQueue           bool
    29  }
    30  
    31  var allPullRequestFeatures = PullRequestFeatures{
    32  	ReviewDecision:       true,
    33  	StatusCheckRollup:    true,
    34  	BranchProtectionRule: true,
    35  	MergeQueue:           true,
    36  }
    37  
    38  type RepositoryFeatures struct {
    39  	IssueTemplateMutation    bool
    40  	IssueTemplateQuery       bool
    41  	PullRequestTemplateQuery bool
    42  	VisibilityField          bool
    43  	AutoMerge                bool
    44  }
    45  
    46  var allRepositoryFeatures = RepositoryFeatures{
    47  	IssueTemplateMutation:    true,
    48  	IssueTemplateQuery:       true,
    49  	PullRequestTemplateQuery: true,
    50  	VisibilityField:          true,
    51  	AutoMerge:                true,
    52  }
    53  
    54  type detector struct {
    55  	host       string
    56  	httpClient *http.Client
    57  }
    58  
    59  func NewDetector(httpClient *http.Client, host string) Detector {
    60  	return &detector{
    61  		httpClient: httpClient,
    62  		host:       host,
    63  	}
    64  }
    65  
    66  func (d *detector) IssueFeatures() (IssueFeatures, error) {
    67  	if !ghinstance.IsEnterprise(d.host) {
    68  		return allIssueFeatures, nil
    69  	}
    70  
    71  	features := IssueFeatures{
    72  		StateReason: false,
    73  	}
    74  
    75  	var featureDetection struct {
    76  		Issue struct {
    77  			Fields []struct {
    78  				Name string
    79  			} `graphql:"fields(includeDeprecated: true)"`
    80  		} `graphql:"Issue: __type(name: \"Issue\")"`
    81  	}
    82  
    83  	gql := api.NewClientFromHTTP(d.httpClient)
    84  	err := gql.Query(d.host, "Issue_fields", &featureDetection, nil)
    85  	if err != nil {
    86  		return features, err
    87  	}
    88  
    89  	for _, field := range featureDetection.Issue.Fields {
    90  		if field.Name == "stateReason" {
    91  			features.StateReason = true
    92  		}
    93  	}
    94  
    95  	return features, nil
    96  }
    97  
    98  func (d *detector) PullRequestFeatures() (PullRequestFeatures, error) {
    99  	// TODO: reinstate the short-circuit once the APIs are fully available on github.com
   100  	// https://github.com/ungtb10d/cli/issues/5778
   101  	//
   102  	// if !ghinstance.IsEnterprise(d.host) {
   103  	// 	return allPullRequestFeatures, nil
   104  	// }
   105  
   106  	features := PullRequestFeatures{
   107  		ReviewDecision:       true,
   108  		StatusCheckRollup:    true,
   109  		BranchProtectionRule: true,
   110  	}
   111  
   112  	var featureDetection struct {
   113  		PullRequest struct {
   114  			Fields []struct {
   115  				Name string
   116  			} `graphql:"fields(includeDeprecated: true)"`
   117  		} `graphql:"PullRequest: __type(name: \"PullRequest\")"`
   118  	}
   119  
   120  	gql := api.NewClientFromHTTP(d.httpClient)
   121  	err := gql.Query(d.host, "PullRequest_fields", &featureDetection, nil)
   122  	if err != nil {
   123  		return features, err
   124  	}
   125  
   126  	for _, field := range featureDetection.PullRequest.Fields {
   127  		if field.Name == "isInMergeQueue" {
   128  			features.MergeQueue = true
   129  		}
   130  	}
   131  
   132  	return features, nil
   133  }
   134  
   135  func (d *detector) RepositoryFeatures() (RepositoryFeatures, error) {
   136  	if !ghinstance.IsEnterprise(d.host) {
   137  		return allRepositoryFeatures, nil
   138  	}
   139  
   140  	features := RepositoryFeatures{
   141  		IssueTemplateQuery:    true,
   142  		IssueTemplateMutation: true,
   143  	}
   144  
   145  	var featureDetection struct {
   146  		Repository struct {
   147  			Fields []struct {
   148  				Name string
   149  			} `graphql:"fields(includeDeprecated: true)"`
   150  		} `graphql:"Repository: __type(name: \"Repository\")"`
   151  	}
   152  
   153  	gql := api.NewClientFromHTTP(d.httpClient)
   154  
   155  	err := gql.Query(d.host, "Repository_fields", &featureDetection, nil)
   156  	if err != nil {
   157  		return features, err
   158  	}
   159  
   160  	for _, field := range featureDetection.Repository.Fields {
   161  		if field.Name == "pullRequestTemplates" {
   162  			features.PullRequestTemplateQuery = true
   163  		}
   164  		if field.Name == "visibility" {
   165  			features.VisibilityField = true
   166  		}
   167  		if field.Name == "autoMergeAllowed" {
   168  			features.AutoMerge = true
   169  		}
   170  	}
   171  
   172  	return features, nil
   173  }