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 }