github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/api/queries_issue.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/ungtb10d/cli/v2/internal/ghrepo" 8 ) 9 10 type IssuesPayload struct { 11 Assigned IssuesAndTotalCount 12 Mentioned IssuesAndTotalCount 13 Authored IssuesAndTotalCount 14 } 15 16 type IssuesAndTotalCount struct { 17 Issues []Issue 18 TotalCount int 19 SearchCapped bool 20 } 21 22 type Issue struct { 23 Typename string `json:"__typename"` 24 ID string 25 Number int 26 Title string 27 URL string 28 State string 29 StateReason string 30 Closed bool 31 Body string 32 CreatedAt time.Time 33 UpdatedAt time.Time 34 ClosedAt *time.Time 35 Comments Comments 36 Author Author 37 Assignees Assignees 38 Labels Labels 39 ProjectCards ProjectCards 40 Milestone *Milestone 41 ReactionGroups ReactionGroups 42 IsPinned bool 43 } 44 45 func (i Issue) IsPullRequest() bool { 46 return i.Typename == "PullRequest" 47 } 48 49 type Assignees struct { 50 Nodes []GitHubUser 51 TotalCount int 52 } 53 54 func (a Assignees) Logins() []string { 55 logins := make([]string, len(a.Nodes)) 56 for i, a := range a.Nodes { 57 logins[i] = a.Login 58 } 59 return logins 60 } 61 62 type Labels struct { 63 Nodes []IssueLabel 64 TotalCount int 65 } 66 67 func (l Labels) Names() []string { 68 names := make([]string, len(l.Nodes)) 69 for i, l := range l.Nodes { 70 names[i] = l.Name 71 } 72 return names 73 } 74 75 type ProjectCards struct { 76 Nodes []*ProjectInfo 77 TotalCount int 78 } 79 80 type ProjectInfo struct { 81 Project struct { 82 Name string `json:"name"` 83 } `json:"project"` 84 Column struct { 85 Name string `json:"name"` 86 } `json:"column"` 87 } 88 89 func (p ProjectCards) ProjectNames() []string { 90 names := make([]string, len(p.Nodes)) 91 for i, c := range p.Nodes { 92 names[i] = c.Project.Name 93 } 94 return names 95 } 96 97 type Milestone struct { 98 Number int `json:"number"` 99 Title string `json:"title"` 100 Description string `json:"description"` 101 DueOn *time.Time `json:"dueOn"` 102 } 103 104 type IssuesDisabledError struct { 105 error 106 } 107 108 type Owner struct { 109 ID string `json:"id,omitempty"` 110 Name string `json:"name,omitempty"` 111 Login string `json:"login"` 112 } 113 114 type Author struct { 115 // adding these breaks generated GraphQL requests 116 //ID string `json:"id,omitempty"` 117 //Name string `json:"name,omitempty"` 118 Login string `json:"login"` 119 } 120 121 // IssueCreate creates an issue in a GitHub repository 122 func IssueCreate(client *Client, repo *Repository, params map[string]interface{}) (*Issue, error) { 123 query := ` 124 mutation IssueCreate($input: CreateIssueInput!) { 125 createIssue(input: $input) { 126 issue { 127 url 128 } 129 } 130 }` 131 132 inputParams := map[string]interface{}{ 133 "repositoryId": repo.ID, 134 } 135 for key, val := range params { 136 inputParams[key] = val 137 } 138 variables := map[string]interface{}{ 139 "input": inputParams, 140 } 141 142 result := struct { 143 CreateIssue struct { 144 Issue Issue 145 } 146 }{} 147 148 err := client.GraphQL(repo.RepoHost(), query, variables, &result) 149 if err != nil { 150 return nil, err 151 } 152 153 return &result.CreateIssue.Issue, nil 154 } 155 156 type IssueStatusOptions struct { 157 Username string 158 Fields []string 159 } 160 161 func IssueStatus(client *Client, repo ghrepo.Interface, options IssueStatusOptions) (*IssuesPayload, error) { 162 type response struct { 163 Repository struct { 164 Assigned struct { 165 TotalCount int 166 Nodes []Issue 167 } 168 Mentioned struct { 169 TotalCount int 170 Nodes []Issue 171 } 172 Authored struct { 173 TotalCount int 174 Nodes []Issue 175 } 176 HasIssuesEnabled bool 177 } 178 } 179 180 fragments := fmt.Sprintf("fragment issue on Issue{%s}", IssueGraphQL(options.Fields)) 181 query := fragments + ` 182 query IssueStatus($owner: String!, $repo: String!, $viewer: String!, $per_page: Int = 10) { 183 repository(owner: $owner, name: $repo) { 184 hasIssuesEnabled 185 assigned: issues(filterBy: {assignee: $viewer, states: OPEN}, first: $per_page, orderBy: {field: UPDATED_AT, direction: DESC}) { 186 totalCount 187 nodes { 188 ...issue 189 } 190 } 191 mentioned: issues(filterBy: {mentioned: $viewer, states: OPEN}, first: $per_page, orderBy: {field: UPDATED_AT, direction: DESC}) { 192 totalCount 193 nodes { 194 ...issue 195 } 196 } 197 authored: issues(filterBy: {createdBy: $viewer, states: OPEN}, first: $per_page, orderBy: {field: UPDATED_AT, direction: DESC}) { 198 totalCount 199 nodes { 200 ...issue 201 } 202 } 203 } 204 }` 205 206 variables := map[string]interface{}{ 207 "owner": repo.RepoOwner(), 208 "repo": repo.RepoName(), 209 "viewer": options.Username, 210 } 211 212 var resp response 213 err := client.GraphQL(repo.RepoHost(), query, variables, &resp) 214 if err != nil { 215 return nil, err 216 } 217 218 if !resp.Repository.HasIssuesEnabled { 219 return nil, fmt.Errorf("the '%s' repository has disabled issues", ghrepo.FullName(repo)) 220 } 221 222 payload := IssuesPayload{ 223 Assigned: IssuesAndTotalCount{ 224 Issues: resp.Repository.Assigned.Nodes, 225 TotalCount: resp.Repository.Assigned.TotalCount, 226 }, 227 Mentioned: IssuesAndTotalCount{ 228 Issues: resp.Repository.Mentioned.Nodes, 229 TotalCount: resp.Repository.Mentioned.TotalCount, 230 }, 231 Authored: IssuesAndTotalCount{ 232 Issues: resp.Repository.Authored.Nodes, 233 TotalCount: resp.Repository.Authored.TotalCount, 234 }, 235 } 236 237 return &payload, nil 238 } 239 240 func (i Issue) Link() string { 241 return i.URL 242 } 243 244 func (i Issue) Identifier() string { 245 return i.ID 246 } 247 248 func (i Issue) CurrentUserComments() []Comment { 249 return i.Comments.CurrentUserComments() 250 }