diff --git a/api/client.go b/api/client.go index 895f29692..7ff1bb6f2 100644 --- a/api/client.go +++ b/api/client.go @@ -28,28 +28,34 @@ const ( var linkRE = regexp.MustCompile(`<([^>]+)>;\s*rel="([^"]+)"`) +// NewClientFromHTTP creates a new Client from an http.Client. func NewClientFromHTTP(httpClient *http.Client) *Client { client := &Client{http: httpClient} return client } +// Client wraps an http.Client to provide GitHub API request methods. type Client struct { http *http.Client } +// HTTP returns the underlying http.Client. func (c *Client) HTTP() *http.Client { return c.http } +// GraphQLError wraps a ghAPI.GraphQLError for GitHub GraphQL API error responses. type GraphQLError struct { *ghAPI.GraphQLError } +// HTTPError wraps a ghAPI.HTTPError with an optional scopes suggestion message. type HTTPError struct { *ghAPI.HTTPError scopesSuggestion string } +// ScopesSuggestion returns a message suggesting additional OAuth scopes if applicable. func (err HTTPError) ScopesSuggestion() string { return err.scopesSuggestion } @@ -112,6 +118,7 @@ func (c Client) REST(hostname string, method string, p string, body io.Reader, d return handleResponse(restClient.Do(method, p, body, data)) } +// RESTWithNext performs a REST request and returns the next page URL along with the parsed response. func (c Client) RESTWithNext(hostname string, method string, p string, body io.Reader, data interface{}) (string, error) { opts := clientOptions(hostname, c.http.Transport) restClient, err := ghAPI.NewRESTClient(opts) @@ -193,6 +200,7 @@ func handleResponse(err error) error { return err } +// GenerateScopeErrorForGQL returns an error with missing scope details if the GraphQL error indicates insufficient scopes. func GenerateScopeErrorForGQL(gqlErr *ghAPI.GraphQLError) error { missing := set.NewStringSet() for _, e := range gqlErr.Errors { diff --git a/api/export_pr.go b/api/export_pr.go index 9b030c39e..7ad358947 100644 --- a/api/export_pr.go +++ b/api/export_pr.go @@ -5,6 +5,7 @@ import ( "strings" ) +// ExportData returns issue data as a map for the specified field names. func (issue *Issue) ExportData(fields []string) map[string]interface{} { v := reflect.ValueOf(issue).Elem() data := map[string]interface{}{} @@ -55,6 +56,7 @@ func (issue *Issue) ExportData(fields []string) map[string]interface{} { return data } +// ExportData returns pull request data as a map for the specified field names. func (pr *PullRequest) ExportData(fields []string) map[string]interface{} { v := reflect.ValueOf(pr).Elem() data := map[string]interface{}{} diff --git a/api/export_repo.go b/api/export_repo.go index a07246ab9..a238a8b67 100644 --- a/api/export_repo.go +++ b/api/export_repo.go @@ -4,6 +4,7 @@ import ( "reflect" ) +// ExportData returns repository data as a map for the specified field names. func (repo *Repository) ExportData(fields []string) map[string]interface{} { v := reflect.ValueOf(repo).Elem() data := map[string]interface{}{} diff --git a/api/http_client.go b/api/http_client.go index 9957f6bc5..2e87b6b24 100644 --- a/api/http_client.go +++ b/api/http_client.go @@ -16,6 +16,7 @@ type tokenGetter interface { ActiveToken(string) (string, string) } +// HTTPClientOptions defines configuration options for creating an HTTP client. type HTTPClientOptions struct { AppVersion string CacheTTL time.Duration @@ -27,6 +28,7 @@ type HTTPClientOptions struct { SkipDefaultHeaders bool } +// NewHTTPClient creates a new http.Client configured with the given options. func NewHTTPClient(opts HTTPClientOptions) (*http.Client, error) { // Provide invalid host, and token values so gh.HTTPClient will not automatically resolve them. // The real host and token are inserted at request time. @@ -71,6 +73,7 @@ func NewHTTPClient(opts HTTPClientOptions) (*http.Client, error) { return client, nil } +// NewCachedHTTPClient wraps an existing http.Client with a cache layer using the given TTL. func NewCachedHTTPClient(httpClient *http.Client, ttl time.Duration) *http.Client { newClient := *httpClient newClient.Transport = AddCacheTTLHeader(httpClient.Transport, ttl) @@ -131,6 +134,7 @@ type funcTripper struct { roundTrip func(*http.Request) (*http.Response, error) } +// RoundTrip executes the wrapped round-trip function. func (tr funcTripper) RoundTrip(req *http.Request) (*http.Response, error) { return tr.roundTrip(req) } diff --git a/api/queries_branch_issue_reference.go b/api/queries_branch_issue_reference.go index 54a9144b0..45dbc1f81 100644 --- a/api/queries_branch_issue_reference.go +++ b/api/queries_branch_issue_reference.go @@ -7,11 +7,13 @@ import ( "github.com/shurcooL/githubv4" ) +// LinkedBranch represents a branch linked to a GitHub issue. type LinkedBranch struct { BranchName string URL string } +// CreateLinkedBranch creates a linked branch for the given issue and returns the branch name. func CreateLinkedBranch(client *Client, host string, repoID, issueID, branchID, branchName string) (string, error) { var mutation struct { CreateLinkedBranch struct { @@ -48,6 +50,7 @@ func CreateLinkedBranch(client *Client, host string, repoID, issueID, branchID, return mutation.CreateLinkedBranch.LinkedBranch.Ref.Name, nil } +// ListLinkedBranches returns all branches linked to the given issue. func ListLinkedBranches(client *Client, repo ghrepo.Interface, issueNumber int) ([]LinkedBranch, error) { var query struct { Repository struct { @@ -89,6 +92,7 @@ func ListLinkedBranches(client *Client, repo ghrepo.Interface, issueNumber int) return branchNames, nil } +// CheckLinkedBranchFeature checks whether the linked branch feature is available on the given host. func CheckLinkedBranchFeature(client *Client, host string) error { var query struct { Name struct { @@ -109,6 +113,7 @@ func CheckLinkedBranchFeature(client *Client, host string) error { return nil } +// FindRepoBranchID returns the repository node ID and the git object ID for the given ref. func FindRepoBranchID(client *Client, repo ghrepo.Interface, ref string) (string, string, error) { var query struct { Repository struct { diff --git a/api/queries_comments.go b/api/queries_comments.go index 8af17fd2a..29581f966 100644 --- a/api/queries_comments.go +++ b/api/queries_comments.go @@ -6,6 +6,7 @@ import ( "github.com/shurcooL/githubv4" ) +// Comments represents a paginated list of comments on an issue or pull request. type Comments struct { Nodes []Comment TotalCount int @@ -15,6 +16,7 @@ type Comments struct { } } +// CurrentUserComments returns only the comments authored by the current viewer. func (cs Comments) CurrentUserComments() []Comment { var comments []Comment for _, c := range cs.Nodes { @@ -25,6 +27,7 @@ func (cs Comments) CurrentUserComments() []Comment { return comments } +// Comment represents a single comment on an issue or pull request. type Comment struct { ID string `json:"id"` Author CommentAuthor `json:"author"` @@ -39,20 +42,24 @@ type Comment struct { ViewerDidAuthor bool `json:"viewerDidAuthor"` } +// CommentCreateInput defines the parameters for creating a new comment. type CommentCreateInput struct { Body string SubjectId string } +// CommentDeleteInput defines the parameters for deleting a comment. type CommentDeleteInput struct { CommentId string } +// CommentUpdateInput defines the parameters for updating a comment. type CommentUpdateInput struct { Body string CommentId string } +// CommentCreate creates a new comment on an issue or pull request and returns the URL of the created comment. func CommentCreate(client *Client, repoHost string, params CommentCreateInput) (string, error) { var mutation struct { AddComment struct { @@ -79,6 +86,7 @@ func CommentCreate(client *Client, repoHost string, params CommentCreateInput) ( return mutation.AddComment.CommentEdge.Node.URL, nil } +// CommentUpdate updates an existing issue comment and returns the URL of the updated comment. func CommentUpdate(client *Client, repoHost string, params CommentUpdateInput) (string, error) { var mutation struct { UpdateIssueComment struct { @@ -103,6 +111,7 @@ func CommentUpdate(client *Client, repoHost string, params CommentUpdateInput) ( return mutation.UpdateIssueComment.IssueComment.URL, nil } +// CommentDelete deletes an issue comment via the GraphQL API. func CommentDelete(client *Client, repoHost string, params CommentDeleteInput) error { var mutation struct { DeleteIssueComment struct { @@ -124,46 +133,57 @@ func CommentDelete(client *Client, repoHost string, params CommentDeleteInput) e return nil } +// Identifier returns the unique ID of the comment. func (c Comment) Identifier() string { return c.ID } +// AuthorLogin returns the login name of the comment author. func (c Comment) AuthorLogin() string { return c.Author.Login } +// Association returns the author's association with the repository. func (c Comment) Association() string { return c.AuthorAssociation } +// Content returns the body text of the comment. func (c Comment) Content() string { return c.Body } +// Created returns the time when the comment was created. func (c Comment) Created() time.Time { return c.CreatedAt } +// HiddenReason returns the reason the comment was minimized, if any. func (c Comment) HiddenReason() string { return c.MinimizedReason } +// IsEdited returns whether the comment has been edited. func (c Comment) IsEdited() bool { return c.IncludesCreatedEdit } +// IsHidden returns whether the comment has been minimized. func (c Comment) IsHidden() bool { return c.IsMinimized } +// Link returns the URL of the comment. func (c Comment) Link() string { return c.URL } +// Reactions returns the reaction groups associated with the comment. func (c Comment) Reactions() ReactionGroups { return c.ReactionGroups } +// Status returns the status of the comment; always empty for regular comments. func (c Comment) Status() string { return "" } diff --git a/api/queries_issue.go b/api/queries_issue.go index 1a8e082ad..11d1edd3a 100644 --- a/api/queries_issue.go +++ b/api/queries_issue.go @@ -8,18 +8,21 @@ import ( "github.com/cli/cli/v2/internal/ghrepo" ) +// IssuesPayload represents categorized issue results for the current user. type IssuesPayload struct { Assigned IssuesAndTotalCount Mentioned IssuesAndTotalCount Authored IssuesAndTotalCount } +// IssuesAndTotalCount represents a list of issues along with pagination metadata. type IssuesAndTotalCount struct { Issues []Issue TotalCount int SearchCapped bool } +// Issue represents a GitHub issue or pull request. type Issue struct { Typename string `json:"__typename"` ID string @@ -49,6 +52,7 @@ type Issue struct { ClosedByPullRequestsReferences ClosedByPullRequestsReferences } +// ClosedByPullRequestsReferences represents pull requests that close an issue. type ClosedByPullRequestsReferences struct { Nodes []struct { ID string @@ -75,15 +79,18 @@ const ( TypePullRequest string = "PullRequest" ) +// IsPullRequest reports whether the issue is actually a pull request. func (i Issue) IsPullRequest() bool { return i.Typename == TypePullRequest } +// Assignees represents users assigned to an issue or pull request. type Assignees struct { Nodes []GitHubUser TotalCount int } +// Logins returns the login usernames of all assignees. func (a Assignees) Logins() []string { logins := make([]string, len(a.Nodes)) for i, a := range a.Nodes { @@ -92,11 +99,13 @@ func (a Assignees) Logins() []string { return logins } +// AssignedActors represents actors (users or bots) assigned to an issue or pull request. type AssignedActors struct { Nodes []Actor TotalCount int } +// Logins returns the login usernames of all assigned actors. func (a AssignedActors) Logins() []string { logins := make([]string, len(a.Nodes)) for i, a := range a.Nodes { @@ -147,11 +156,13 @@ func (a AssignedActors) DisplayNames() []string { return displayNames } +// Labels represents the set of labels applied to an issue or pull request. type Labels struct { Nodes []IssueLabel TotalCount int } +// Names returns the names of all labels. func (l Labels) Names() []string { names := make([]string, len(l.Nodes)) for i, l := range l.Nodes { @@ -160,16 +171,19 @@ func (l Labels) Names() []string { return names } +// ProjectCards represents classic project cards associated with an issue or pull request. type ProjectCards struct { Nodes []*ProjectInfo TotalCount int } +// ProjectItems represents ProjectV2 items associated with an issue or pull request. type ProjectItems struct { Nodes []*ProjectV2Item TotalCount int } +// ProjectInfo represents a classic project card's project and column names. type ProjectInfo struct { Project struct { Name string `json:"name"` @@ -179,22 +193,26 @@ type ProjectInfo struct { } `json:"column"` } +// ProjectV2Item represents an item within a GitHub ProjectV2. type ProjectV2Item struct { ID string `json:"id"` Project ProjectV2ItemProject Status ProjectV2ItemStatus } +// ProjectV2ItemProject represents the project associated with a ProjectV2 item. type ProjectV2ItemProject struct { ID string `json:"id"` Title string `json:"title"` } +// ProjectV2ItemStatus represents the status field of a ProjectV2 item. type ProjectV2ItemStatus struct { OptionID string `json:"optionId"` Name string `json:"name"` } +// ProjectNames returns the project names from all classic project cards. func (p ProjectCards) ProjectNames() []string { names := make([]string, len(p.Nodes)) for i, c := range p.Nodes { @@ -203,6 +221,7 @@ func (p ProjectCards) ProjectNames() []string { return names } +// ProjectTitles returns the project titles from all ProjectV2 items. func (p ProjectItems) ProjectTitles() []string { titles := make([]string, len(p.Nodes)) for i, c := range p.Nodes { @@ -211,6 +230,7 @@ func (p ProjectItems) ProjectTitles() []string { return titles } +// Milestone represents a GitHub milestone. type Milestone struct { Number int `json:"number"` Title string `json:"title"` @@ -218,22 +238,26 @@ type Milestone struct { DueOn *time.Time `json:"dueOn"` } +// IssuesDisabledError indicates that issues are disabled for a repository. type IssuesDisabledError struct { error } +// Owner represents the owner of a GitHub repository. type Owner struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Login string `json:"login"` } +// Author represents the author of an issue, pull request, or comment. type Author struct { ID string Name string Login string } +// MarshalJSON implements the json.Marshaler interface for Author. func (author Author) MarshalJSON() ([]byte, error) { if author.ID == "" { return json.Marshal(map[string]interface{}{ @@ -249,6 +273,7 @@ func (author Author) MarshalJSON() ([]byte, error) { }) } +// CommentAuthor represents the author of a comment with only a login field. type CommentAuthor struct { Login string `json:"login"` // Unfortunately, there is no easy way to add "id" and "name" fields to this struct because it's being @@ -317,11 +342,13 @@ func IssueCreate(client *Client, repo *Repository, params map[string]interface{} return issue, nil } +// IssueStatusOptions specifies options for querying the current user's issue status. type IssueStatusOptions struct { Username string Fields []string } +// IssueStatus returns issues assigned to, mentioning, or authored by the current user. func IssueStatus(client *Client, repo ghrepo.Interface, options IssueStatusOptions) (*IssuesPayload, error) { type response struct { Repository struct { @@ -401,14 +428,17 @@ func IssueStatus(client *Client, repo ghrepo.Interface, options IssueStatusOptio return &payload, nil } +// Link returns the URL of the issue. func (i Issue) Link() string { return i.URL } +// Identifier returns the unique ID of the issue. func (i Issue) Identifier() string { return i.ID } +// CurrentUserComments returns comments on the issue authored by the current user. func (i Issue) CurrentUserComments() []Comment { return i.Comments.CurrentUserComments() } diff --git a/api/queries_org.go b/api/queries_org.go index f2e93342e..ac2ced108 100644 --- a/api/queries_org.go +++ b/api/queries_org.go @@ -43,6 +43,7 @@ func OrganizationProjects(client *Client, repo ghrepo.Interface) ([]RepoProject, return projects, nil } +// OrgTeam represents a team within a GitHub organization. type OrgTeam struct { ID string Slug string diff --git a/api/queries_pr.go b/api/queries_pr.go index c38018a68..ce224034d 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -13,20 +13,26 @@ import ( "github.com/shurcooL/githubv4" ) +// PullRequestAndTotalCount represents a list of pull requests along with the total count and search cap status. type PullRequestAndTotalCount struct { TotalCount int PullRequests []PullRequest SearchCapped bool } +// PullRequestMergeable represents the mergeability state of a pull request. type PullRequestMergeable string const ( + // PullRequestMergeableConflicting indicates the pull request has merge conflicts. PullRequestMergeableConflicting PullRequestMergeable = "CONFLICTING" - PullRequestMergeableMergeable PullRequestMergeable = "MERGEABLE" - PullRequestMergeableUnknown PullRequestMergeable = "UNKNOWN" + // PullRequestMergeableMergeable indicates the pull request can be merged. + PullRequestMergeableMergeable PullRequestMergeable = "MERGEABLE" + // PullRequestMergeableUnknown indicates the mergeability state is not yet known. + PullRequestMergeableUnknown PullRequestMergeable = "UNKNOWN" ) +// PullRequest represents a GitHub pull request with all associated metadata. type PullRequest struct { ID string FullDatabaseID string @@ -102,18 +108,22 @@ type PullRequest struct { ClosingIssuesReferences ClosingIssuesReferences } +// StatusCheckRollupNode represents a node in the status check rollup containing a commit. type StatusCheckRollupNode struct { Commit StatusCheckRollupCommit } +// StatusCheckRollupCommit represents a commit with its associated status check rollup. type StatusCheckRollupCommit struct { StatusCheckRollup CommitStatusCheckRollup } +// CommitStatusCheckRollup represents the rollup of status checks for a commit. type CommitStatusCheckRollup struct { Contexts CheckContexts } +// ClosingIssuesReferences represents issues that will be closed when a pull request is merged. type ClosingIssuesReferences struct { Nodes []struct { ID string @@ -138,22 +148,37 @@ type ClosingIssuesReferences struct { type CheckRunState string const ( + // CheckRunStateActionRequired indicates the check run requires action. CheckRunStateActionRequired CheckRunState = "ACTION_REQUIRED" - CheckRunStateCancelled CheckRunState = "CANCELLED" - CheckRunStateCompleted CheckRunState = "COMPLETED" - CheckRunStateFailure CheckRunState = "FAILURE" - CheckRunStateInProgress CheckRunState = "IN_PROGRESS" - CheckRunStateNeutral CheckRunState = "NEUTRAL" - CheckRunStatePending CheckRunState = "PENDING" - CheckRunStateQueued CheckRunState = "QUEUED" - CheckRunStateSkipped CheckRunState = "SKIPPED" - CheckRunStateStale CheckRunState = "STALE" + // CheckRunStateCancelled indicates the check run was cancelled. + CheckRunStateCancelled CheckRunState = "CANCELLED" + // CheckRunStateCompleted indicates the check run has completed. + CheckRunStateCompleted CheckRunState = "COMPLETED" + // CheckRunStateFailure indicates the check run has failed. + CheckRunStateFailure CheckRunState = "FAILURE" + // CheckRunStateInProgress indicates the check run is currently in progress. + CheckRunStateInProgress CheckRunState = "IN_PROGRESS" + // CheckRunStateNeutral indicates the check run completed with a neutral result. + CheckRunStateNeutral CheckRunState = "NEUTRAL" + // CheckRunStatePending indicates the check run is pending. + CheckRunStatePending CheckRunState = "PENDING" + // CheckRunStateQueued indicates the check run is queued. + CheckRunStateQueued CheckRunState = "QUEUED" + // CheckRunStateSkipped indicates the check run was skipped. + CheckRunStateSkipped CheckRunState = "SKIPPED" + // CheckRunStateStale indicates the check run is stale. + CheckRunStateStale CheckRunState = "STALE" + // CheckRunStateStartupFailure indicates the check run failed during startup. CheckRunStateStartupFailure CheckRunState = "STARTUP_FAILURE" - CheckRunStateSuccess CheckRunState = "SUCCESS" - CheckRunStateTimedOut CheckRunState = "TIMED_OUT" - CheckRunStateWaiting CheckRunState = "WAITING" + // CheckRunStateSuccess indicates the check run succeeded. + CheckRunStateSuccess CheckRunState = "SUCCESS" + // CheckRunStateTimedOut indicates the check run timed out. + CheckRunStateTimedOut CheckRunState = "TIMED_OUT" + // CheckRunStateWaiting indicates the check run is waiting. + CheckRunStateWaiting CheckRunState = "WAITING" ) +// CheckRunCountByState represents a count of check runs grouped by their state. type CheckRunCountByState struct { State CheckRunState Count int @@ -163,13 +188,19 @@ type CheckRunCountByState struct { type StatusState string const ( - StatusStateError StatusState = "ERROR" + // StatusStateError indicates the status check reported an error. + StatusStateError StatusState = "ERROR" + // StatusStateExpected indicates the status check is expected. StatusStateExpected StatusState = "EXPECTED" - StatusStateFailure StatusState = "FAILURE" - StatusStatePending StatusState = "PENDING" - StatusStateSuccess StatusState = "SUCCESS" + // StatusStateFailure indicates the status check has failed. + StatusStateFailure StatusState = "FAILURE" + // StatusStatePending indicates the status check is pending. + StatusStatePending StatusState = "PENDING" + // StatusStateSuccess indicates the status check succeeded. + StatusStateSuccess StatusState = "SUCCESS" ) +// StatusContextCountByState represents a count of status contexts grouped by their state. type StatusContextCountByState struct { State StatusState Count int @@ -179,29 +210,45 @@ type StatusContextCountByState struct { type CheckStatusState string const ( - CheckStatusStateCompleted CheckStatusState = "COMPLETED" + // CheckStatusStateCompleted indicates the check has completed. + CheckStatusStateCompleted CheckStatusState = "COMPLETED" + // CheckStatusStateInProgress indicates the check is in progress. CheckStatusStateInProgress CheckStatusState = "IN_PROGRESS" - CheckStatusStatePending CheckStatusState = "PENDING" - CheckStatusStateQueued CheckStatusState = "QUEUED" - CheckStatusStateRequested CheckStatusState = "REQUESTED" - CheckStatusStateWaiting CheckStatusState = "WAITING" + // CheckStatusStatePending indicates the check is pending. + CheckStatusStatePending CheckStatusState = "PENDING" + // CheckStatusStateQueued indicates the check is queued. + CheckStatusStateQueued CheckStatusState = "QUEUED" + // CheckStatusStateRequested indicates the check has been requested. + CheckStatusStateRequested CheckStatusState = "REQUESTED" + // CheckStatusStateWaiting indicates the check is waiting. + CheckStatusStateWaiting CheckStatusState = "WAITING" ) // https://docs.github.com/en/graphql/reference/enums#checkconclusionstate type CheckConclusionState string const ( + // CheckConclusionStateActionRequired indicates the check conclusion requires action. CheckConclusionStateActionRequired CheckConclusionState = "ACTION_REQUIRED" - CheckConclusionStateCancelled CheckConclusionState = "CANCELLED" - CheckConclusionStateFailure CheckConclusionState = "FAILURE" - CheckConclusionStateNeutral CheckConclusionState = "NEUTRAL" - CheckConclusionStateSkipped CheckConclusionState = "SKIPPED" - CheckConclusionStateStale CheckConclusionState = "STALE" + // CheckConclusionStateCancelled indicates the check was cancelled. + CheckConclusionStateCancelled CheckConclusionState = "CANCELLED" + // CheckConclusionStateFailure indicates the check concluded with a failure. + CheckConclusionStateFailure CheckConclusionState = "FAILURE" + // CheckConclusionStateNeutral indicates the check concluded with a neutral result. + CheckConclusionStateNeutral CheckConclusionState = "NEUTRAL" + // CheckConclusionStateSkipped indicates the check was skipped. + CheckConclusionStateSkipped CheckConclusionState = "SKIPPED" + // CheckConclusionStateStale indicates the check conclusion is stale. + CheckConclusionStateStale CheckConclusionState = "STALE" + // CheckConclusionStateStartupFailure indicates the check failed during startup. CheckConclusionStateStartupFailure CheckConclusionState = "STARTUP_FAILURE" - CheckConclusionStateSuccess CheckConclusionState = "SUCCESS" - CheckConclusionStateTimedOut CheckConclusionState = "TIMED_OUT" + // CheckConclusionStateSuccess indicates the check concluded successfully. + CheckConclusionStateSuccess CheckConclusionState = "SUCCESS" + // CheckConclusionStateTimedOut indicates the check conclusion timed out. + CheckConclusionStateTimedOut CheckConclusionState = "TIMED_OUT" ) +// CheckContexts represents the check and status context information for a commit. type CheckContexts struct { // These fields are available on newer versions of the GraphQL API // to support summary counts by state @@ -219,6 +266,7 @@ type CheckContexts struct { } } +// CheckContext represents a single check run or status context for a commit. type CheckContext struct { TypeName string `json:"__typename"` Name string `json:"name"` @@ -241,25 +289,30 @@ type CheckContext struct { CreatedAt time.Time `json:"createdAt"` } +// CheckSuite represents a GitHub check suite containing a workflow run. type CheckSuite struct { WorkflowRun WorkflowRun `json:"workflowRun"` } +// WorkflowRun represents a GitHub Actions workflow run triggered by an event. type WorkflowRun struct { Event string `json:"event"` Workflow Workflow `json:"workflow"` } +// Workflow represents a GitHub Actions workflow. type Workflow struct { Name string `json:"name"` } +// PRRepository represents a repository associated with a pull request. type PRRepository struct { ID string `json:"id"` Name string `json:"name"` NameWithOwner string `json:"nameWithOwner"` } +// AutoMergeRequest represents an auto-merge configuration for a pull request. type AutoMergeRequest struct { AuthorEmail *string `json:"authorEmail"` CommitBody *string `json:"commitBody"` @@ -275,6 +328,7 @@ type Commit struct { OID string `json:"oid"` } +// PullRequestCommit represents a commit associated with a pull request. type PullRequestCommit struct { Commit PullRequestCommitCommit } @@ -295,6 +349,7 @@ type PullRequestCommitCommit struct { AuthoredDate time.Time } +// PullRequestFile represents a file changed in a pull request. type PullRequestFile struct { Path string `json:"path"` Additions int `json:"additions"` @@ -302,12 +357,14 @@ type PullRequestFile struct { ChangeType string `json:"changeType"` } +// ReviewRequests represents the review requests on a pull request. type ReviewRequests struct { Nodes []struct { RequestedReviewer RequestedReviewer } } +// RequestedReviewer represents a user, bot, or team requested for review on a pull request. type RequestedReviewer struct { TypeName string `json:"__typename"` Login string `json:"login"` @@ -321,6 +378,7 @@ type RequestedReviewer struct { const teamTypeName = "Team" const botTypeName = "Bot" +// LoginOrSlug returns the login for users or the org/slug for teams. func (r RequestedReviewer) LoginOrSlug() string { if r.TypeName == teamTypeName { return fmt.Sprintf("%s/%s", r.Organization.Login, r.Slug) @@ -344,6 +402,7 @@ func (r RequestedReviewer) DisplayName() string { return r.Login } +// Logins returns the login or slug identifiers for all requested reviewers. func (r ReviewRequests) Logins() []string { logins := make([]string, len(r.Nodes)) for i, r := range r.Nodes { @@ -361,6 +420,7 @@ func (r ReviewRequests) DisplayNames() []string { return names } +// HeadLabel returns the head branch label, including the owner prefix for cross-repository pull requests. func (pr PullRequest) HeadLabel() string { if pr.IsCrossRepository { return fmt.Sprintf("%s:%s", pr.HeadRepositoryOwner.Login, pr.HeadRefName) @@ -368,28 +428,34 @@ func (pr PullRequest) HeadLabel() string { return pr.HeadRefName } +// Link returns the URL of the pull request. func (pr PullRequest) Link() string { return pr.URL } +// Identifier returns the GraphQL node ID of the pull request. func (pr PullRequest) Identifier() string { return pr.ID } +// CurrentUserComments returns the comments on the pull request authored by the current user. func (pr PullRequest) CurrentUserComments() []Comment { return pr.Comments.CurrentUserComments() } +// IsOpen returns true if the pull request state is open. func (pr PullRequest) IsOpen() bool { return pr.State == "OPEN" } +// PullRequestReviewStatus represents the review decision status of a pull request. type PullRequestReviewStatus struct { ChangesRequested bool Approved bool ReviewRequired bool } +// ReviewStatus returns the review decision status of the pull request. func (pr *PullRequest) ReviewStatus() PullRequestReviewStatus { var status PullRequestReviewStatus switch pr.ReviewDecision { @@ -403,6 +469,7 @@ func (pr *PullRequest) ReviewStatus() PullRequestReviewStatus { return status } +// PullRequestChecksStatus represents the summary of CI check statuses for a pull request. type PullRequestChecksStatus struct { Pending int Failing int @@ -410,6 +477,7 @@ type PullRequestChecksStatus struct { Total int } +// ChecksStatus returns the aggregated CI checks status for the pull request. func (pr *PullRequest) ChecksStatus() PullRequestChecksStatus { var summary PullRequestChecksStatus @@ -542,6 +610,7 @@ func parseCheckStatusFromCheckConclusionState(state CheckConclusionState) checkS } } +// DisplayableReviews returns the pull request reviews that are suitable for display, excluding pending and empty comment reviews. func (pr *PullRequest) DisplayableReviews() PullRequestReviews { published := []PullRequestReview{} for _, prr := range pr.Reviews.Nodes { @@ -904,6 +973,7 @@ type ReviewerUser struct { AssignableUser } +// NewReviewerUser creates a new ReviewerUser with the given login and name. func NewReviewerUser(login, name string) ReviewerUser { return ReviewerUser{ AssignableUser: NewAssignableUser("", login, name), @@ -917,12 +987,14 @@ type ReviewerBot struct { AssignableBot } +// NewReviewerBot creates a new ReviewerBot with the given login. func NewReviewerBot(login string) ReviewerBot { return ReviewerBot{ AssignableBot: NewAssignableBot("", login), } } +// DisplayName returns a user-friendly name for the bot reviewer. func (b ReviewerBot) DisplayName() string { if b.login == CopilotReviewerLogin { return fmt.Sprintf("%s (AI)", CopilotActorName) @@ -943,14 +1015,17 @@ func NewReviewerTeam(orgName, teamSlug string) ReviewerTeam { return ReviewerTeam{org: orgName, teamSlug: teamSlug} } +// DisplayName returns the org/slug display name for the team reviewer. func (r ReviewerTeam) DisplayName() string { return fmt.Sprintf("%s/%s", r.org, r.teamSlug) } +// Login returns the org/slug identifier for the team reviewer. func (r ReviewerTeam) Login() string { return fmt.Sprintf("%s/%s", r.org, r.teamSlug) } +// Slug returns the team slug for the team reviewer. func (r ReviewerTeam) Slug() string { return r.teamSlug } @@ -1106,6 +1181,7 @@ func SuggestedReviewerActors(client *Client, repo ghrepo.Interface, prID string, return candidates, moreResults, nil } +// UpdatePullRequestBranch updates the head branch of a pull request with the latest upstream changes. func UpdatePullRequestBranch(client *Client, repo ghrepo.Interface, params githubv4.UpdatePullRequestBranchInput) error { var mutation struct { UpdatePullRequestBranch struct { @@ -1129,6 +1205,7 @@ func isBlank(v interface{}) bool { } } +// PullRequestClose closes a pull request by its ID. func PullRequestClose(httpClient *http.Client, repo ghrepo.Interface, prID string) error { var mutation struct { ClosePullRequest struct { @@ -1148,6 +1225,7 @@ func PullRequestClose(httpClient *http.Client, repo ghrepo.Interface, prID strin return client.Mutate(repo.RepoHost(), "PullRequestClose", &mutation, variables) } +// PullRequestReopen reopens a previously closed pull request by its ID. func PullRequestReopen(httpClient *http.Client, repo ghrepo.Interface, prID string) error { var mutation struct { ReopenPullRequest struct { @@ -1167,6 +1245,7 @@ func PullRequestReopen(httpClient *http.Client, repo ghrepo.Interface, prID stri return client.Mutate(repo.RepoHost(), "PullRequestReopen", &mutation, variables) } +// PullRequestReady marks a draft pull request as ready for review. func PullRequestReady(client *Client, repo ghrepo.Interface, pr *PullRequest) error { var mutation struct { MarkPullRequestReadyForReview struct { @@ -1185,6 +1264,7 @@ func PullRequestReady(client *Client, repo ghrepo.Interface, pr *PullRequest) er return client.Mutate(repo.RepoHost(), "PullRequestReadyForReview", &mutation, variables) } +// PullRequestRevert reverts a merged pull request and returns the newly created revert pull request. func PullRequestRevert(client *Client, repo ghrepo.Interface, params githubv4.RevertPullRequestInput) (*PullRequest, error) { var mutation struct { RevertPullRequest struct { @@ -1216,6 +1296,7 @@ func PullRequestRevert(client *Client, repo ghrepo.Interface, params githubv4.Re return revertPR, nil } +// ConvertPullRequestToDraft converts a pull request to draft state. func ConvertPullRequestToDraft(client *Client, repo ghrepo.Interface, pr *PullRequest) error { var mutation struct { ConvertPullRequestToDraft struct { @@ -1234,17 +1315,20 @@ func ConvertPullRequestToDraft(client *Client, repo ghrepo.Interface, pr *PullRe return client.Mutate(repo.RepoHost(), "ConvertPullRequestToDraft", &mutation, variables) } +// BranchDeleteRemote deletes a branch from the remote repository. func BranchDeleteRemote(client *Client, repo ghrepo.Interface, branch string) error { path := fmt.Sprintf("repos/%s/%s/git/refs/heads/%s", repo.RepoOwner(), repo.RepoName(), url.PathEscape(branch)) return client.REST(repo.RepoHost(), "DELETE", path, nil, nil) } +// RefComparison represents the comparison between two Git references. type RefComparison struct { AheadBy int BehindBy int Status string } +// ComparePullRequestBaseBranchWith compares the base branch of a pull request with the given head reference. func ComparePullRequestBaseBranchWith(client *Client, repo ghrepo.Interface, prNumber int, headRef string) (*RefComparison, error) { query := `query ComparePullRequestBaseBranchWith($owner: String!, $repo: String!, $pullRequestNumber: Int!, $headRef: String!) { repository(owner: $owner, name: $repo) { diff --git a/api/queries_pr_review.go b/api/queries_pr_review.go index d5565b54b..e0afb2c9e 100644 --- a/api/queries_pr_review.go +++ b/api/queries_pr_review.go @@ -7,19 +7,25 @@ import ( "github.com/shurcooL/githubv4" ) +// PullRequestReviewState represents the type of review event for a pull request. type PullRequestReviewState int const ( + // ReviewApprove is a review that approves the pull request. ReviewApprove PullRequestReviewState = iota + // ReviewRequestChanges is a review that requests changes on the pull request. ReviewRequestChanges + // ReviewComment is a review that leaves a comment without approval or change request. ReviewComment ) +// PullRequestReviewInput defines the parameters for submitting a pull request review. type PullRequestReviewInput struct { Body string State PullRequestReviewState } +// PullRequestReviews represents a paginated list of pull request reviews. type PullRequestReviews struct { Nodes []PullRequestReview PageInfo struct { @@ -29,6 +35,7 @@ type PullRequestReviews struct { TotalCount int } +// PullRequestReview represents a single review on a pull request. type PullRequestReview struct { ID string `json:"id"` Author CommentAuthor `json:"author"` @@ -42,6 +49,7 @@ type PullRequestReview struct { Commit Commit `json:"commit"` } +// AddReview submits a review for the given pull request via the GraphQL API. func AddReview(client *Client, repo ghrepo.Interface, pr *PullRequest, input *PullRequestReviewInput) error { var mutation struct { AddPullRequestReview struct { @@ -69,22 +77,27 @@ func AddReview(client *Client, repo ghrepo.Interface, pr *PullRequest, input *Pu return client.Mutate(repo.RepoHost(), "PullRequestReviewAdd", &mutation, variables) } +// Identifier returns the unique ID of the review. func (prr PullRequestReview) Identifier() string { return prr.ID } +// AuthorLogin returns the login name of the review author. func (prr PullRequestReview) AuthorLogin() string { return prr.Author.Login } +// Association returns the author's association with the repository. func (prr PullRequestReview) Association() string { return prr.AuthorAssociation } +// Content returns the body text of the review. func (prr PullRequestReview) Content() string { return prr.Body } +// Created returns the time when the review was submitted. func (prr PullRequestReview) Created() time.Time { if prr.SubmittedAt == nil { return time.Time{} @@ -92,26 +105,32 @@ func (prr PullRequestReview) Created() time.Time { return *prr.SubmittedAt } +// HiddenReason returns the reason the review was hidden; always empty for reviews. func (prr PullRequestReview) HiddenReason() string { return "" } +// IsEdited returns whether the review has been edited. func (prr PullRequestReview) IsEdited() bool { return prr.IncludesCreatedEdit } +// IsHidden returns whether the review is hidden; always false for reviews. func (prr PullRequestReview) IsHidden() bool { return false } +// Link returns the URL of the review. func (prr PullRequestReview) Link() string { return prr.URL } +// Reactions returns the reaction groups associated with the review. func (prr PullRequestReview) Reactions() ReactionGroups { return prr.ReactionGroups } +// Status returns the review state (e.g., APPROVED, CHANGES_REQUESTED). func (prr PullRequestReview) Status() string { return prr.State } diff --git a/api/queries_projects_v2.go b/api/queries_projects_v2.go index 0126c1caa..ed62b2313 100644 --- a/api/queries_projects_v2.go +++ b/api/queries_projects_v2.go @@ -17,6 +17,7 @@ const ( errorProjectsV2PullRequestField = "Field 'projectItems' doesn't exist on type 'PullRequest'" ) +// ProjectV2 represents a GitHub Projects (v2) project. type ProjectV2 struct { ID string `json:"id"` Title string `json:"title"` diff --git a/api/queries_repo.go b/api/queries_repo.go index d8ffa191d..0f2e7c457 100644 --- a/api/queries_repo.go +++ b/api/queries_repo.go @@ -140,6 +140,7 @@ type RepositoryOwner struct { Login string `json:"login"` } +// GitHubUser represents a GitHub user with basic profile information. type GitHubUser struct { ID string `json:"id"` Login string `json:"login"` @@ -164,33 +165,39 @@ type BranchRef struct { Name string `json:"name"` } +// CodeOfConduct represents a repository's code of conduct. type CodeOfConduct struct { Key string `json:"key"` Name string `json:"name"` URL string `json:"url"` } +// RepositoryLicense represents the license associated with a repository. type RepositoryLicense struct { Key string `json:"key"` Name string `json:"name"` Nickname string `json:"nickname"` } +// ContactLink represents a contact link configured for a repository. type ContactLink struct { About string `json:"about"` Name string `json:"name"` URL string `json:"url"` } +// FundingLink represents a funding platform link for a repository. type FundingLink struct { Platform string `json:"platform"` URL string `json:"url"` } +// CodingLanguage represents a programming language used in a repository. type CodingLanguage struct { Name string `json:"name"` } +// IssueTemplate represents an issue template defined in a repository. type IssueTemplate struct { Name string `json:"name"` Title string `json:"title"` @@ -198,15 +205,18 @@ type IssueTemplate struct { About string `json:"about"` } +// PullRequestTemplate represents a pull request template defined in a repository. type PullRequestTemplate struct { Filename string `json:"filename"` Body string `json:"body"` } +// RepositoryTopic represents a topic tag associated with a repository. type RepositoryTopic struct { Name string `json:"name"` } +// RepositoryRelease represents a release published in a repository. type RepositoryRelease struct { Name string `json:"name"` TagName string `json:"tagName"` @@ -214,6 +224,7 @@ type RepositoryRelease struct { PublishedAt time.Time `json:"publishedAt"` } +// IssueLabel represents a label that can be applied to issues and pull requests. type IssueLabel struct { ID string `json:"id"` Name string `json:"name"` @@ -221,6 +232,7 @@ type IssueLabel struct { Color string `json:"color"` } +// License represents a software license with its full details from the GitHub API. type License struct { Key string `json:"key"` Name string `json:"name"` @@ -237,6 +249,7 @@ type License struct { Featured bool `json:"featured"` } +// GitIgnore represents a gitignore template from the GitHub API. type GitIgnore struct { Name string `json:"name"` Source string `json:"source"` @@ -277,6 +290,7 @@ func (r Repository) ViewerCanTriage() bool { } } +// FetchRepository queries the GitHub GraphQL API for a repository with the specified fields. func FetchRepository(client *Client, repo ghrepo.Interface, fields []string) (*Repository, error) { query := fmt.Sprintf(`query RepositoryInfo($owner: String!, $name: String!) { repository(owner: $owner, name: $name) {%s} @@ -309,6 +323,7 @@ func FetchRepository(client *Client, repo ghrepo.Interface, fields []string) (*R return InitRepoHostname(result.Repository, repo.RepoHost()), nil } +// GitHubRepo fetches detailed repository information including its parent, if any. func GitHubRepo(client *Client, repo ghrepo.Interface) (*Repository, error) { query := ` fragment repo on Repository { @@ -362,6 +377,7 @@ func GitHubRepo(client *Client, repo ghrepo.Interface) (*Repository, error) { return InitRepoHostname(result.Repository, repo.RepoHost()), nil } +// RepoDefaultBranch returns the name of the default branch for a repository. func RepoDefaultBranch(client *Client, repo ghrepo.Interface) (string, error) { if r, ok := repo.(*Repository); ok && r.DefaultBranchRef.Name != "" { return r.DefaultBranchRef.Name, nil @@ -374,6 +390,7 @@ func RepoDefaultBranch(client *Client, repo ghrepo.Interface) (string, error) { return r.DefaultBranchRef.Name, nil } +// CanPushToRepo reports whether the current user has push access to the repository. func CanPushToRepo(httpClient *http.Client, repo ghrepo.Interface) (bool, error) { if r, ok := repo.(*Repository); ok && r.ViewerPermission != "" { return r.ViewerCanPush(), nil @@ -520,6 +537,7 @@ func RepoNetwork(client *Client, repos []ghrepo.Interface) (RepoNetworkResult, e return result, nil } +// InitRepoHostname sets the hostname on a repository and its parent, if present. func InitRepoHostname(repo *Repository, hostname string) *Repository { repo.hostname = hostname if repo.Parent != nil { @@ -619,6 +637,7 @@ func RenameRepo(client *Client, repo ghrepo.Interface, newRepoName string) (*Rep }, nil } +// LastCommit returns the most recent commit on the default branch of a repository. func LastCommit(client *Client, repo ghrepo.Interface) (*Commit, error) { var responseData struct { Repository struct { @@ -686,6 +705,7 @@ func RepoFindForks(client *Client, repo ghrepo.Interface, limit int) ([]*Reposit return results, nil } +// RepoMetadataResult holds pre-fetched metadata for issues and pull requests. type RepoMetadataResult struct { CurrentLogin string AssignableUsers []AssignableUser @@ -697,6 +717,7 @@ type RepoMetadataResult struct { Teams []OrgTeam } +// MembersToIDs resolves user or actor login names to their corresponding node IDs. func (m *RepoMetadataResult) MembersToIDs(names []string) ([]string, error) { var ids []string for _, assigneeLogin := range names { @@ -733,6 +754,7 @@ func (m *RepoMetadataResult) MembersToIDs(names []string) ([]string, error) { return ids, nil } +// TeamsToIDs resolves team slugs to their corresponding node IDs. func (m *RepoMetadataResult) TeamsToIDs(names []string) ([]string, error) { var ids []string for _, teamSlug := range names { @@ -752,6 +774,7 @@ func (m *RepoMetadataResult) TeamsToIDs(names []string) ([]string, error) { return ids, nil } +// LabelsToIDs resolves label names to their corresponding node IDs. func (m *RepoMetadataResult) LabelsToIDs(names []string) ([]string, error) { var ids []string for _, labelName := range names { @@ -818,6 +841,7 @@ func (m *RepoMetadataResult) v2ProjectTitleToID(title string) (string, bool) { return "", false } +// ProjectTitlesToPaths resolves project titles to their resource paths, checking both v1 and v2 projects. func ProjectTitlesToPaths(client *Client, repo ghrepo.Interface, titles []string, projectsV1Support gh.ProjectsV1Support) ([]string, error) { paths := make([]string, 0, len(titles)) matchedPaths := map[string]struct{}{} @@ -885,6 +909,7 @@ func ProjectTitlesToPaths(client *Client, repo ghrepo.Interface, titles []string return paths, nil } +// MilestoneToID resolves a milestone title to its corresponding node ID. func (m *RepoMetadataResult) MilestoneToID(title string) (string, error) { for _, m := range m.Milestones { if strings.EqualFold(title, m.Title) { @@ -894,6 +919,7 @@ func (m *RepoMetadataResult) MilestoneToID(title string) (string, error) { return "", fmt.Errorf("'%s' not found", title) } +// Merge combines another RepoMetadataResult into the receiver, preferring non-empty values from m2. func (m *RepoMetadataResult) Merge(m2 *RepoMetadataResult) { if len(m2.AssignableUsers) > 0 || len(m.AssignableUsers) == 0 { m.AssignableUsers = m2.AssignableUsers @@ -916,6 +942,7 @@ func (m *RepoMetadataResult) Merge(m2 *RepoMetadataResult) { } } +// RepoMetadataInput specifies which categories of repository metadata to fetch. type RepoMetadataInput struct { Assignees bool ActorAssignees bool @@ -1035,6 +1062,7 @@ func RepoMetadata(client *Client, repo ghrepo.Interface, input RepoMetadataInput return &result, nil } +// RepoProject represents a GitHub classic project (v1) associated with a repository. type RepoProject struct { ID string `json:"id"` Name string `json:"name"` @@ -1085,8 +1113,10 @@ const CopilotAssigneeLogin = "copilot-swe-agent" // Expected login for Copilot when retrieved as a Pull Request Reviewer. const CopilotReviewerLogin = "copilot-pull-request-reviewer" +// CopilotActorName is the display name used for the Copilot actor. const CopilotActorName = "Copilot" +// AssignableActor defines the interface for entities that can be assigned to issues or pull requests. type AssignableActor interface { DisplayName() string ID() string @@ -1095,13 +1125,14 @@ type AssignableActor interface { sealedAssignableActor() } -// Always a user +// AssignableUser represents a user that can be assigned to issues or pull requests. type AssignableUser struct { id string login string name string } +// NewAssignableUser creates a new AssignableUser with the given id, login, and name. func NewAssignableUser(id, login, name string) AssignableUser { return AssignableUser{ id: id, @@ -1118,25 +1149,30 @@ func (u AssignableUser) DisplayName() string { return u.login } +// ID returns the node ID of the user. func (u AssignableUser) ID() string { return u.id } +// Login returns the login name of the user. func (u AssignableUser) Login() string { return u.login } +// Name returns the display name of the user. func (u AssignableUser) Name() string { return u.name } func (u AssignableUser) sealedAssignableActor() {} +// AssignableBot represents a bot account that can be assigned to issues or pull requests. type AssignableBot struct { id string login string } +// NewAssignableBot creates a new AssignableBot with the given id and login. func NewAssignableBot(id, login string) AssignableBot { return AssignableBot{ id: id, @@ -1144,6 +1180,7 @@ func NewAssignableBot(id, login string) AssignableBot { } } +// DisplayName returns a formatted display name for the bot. func (b AssignableBot) DisplayName() string { if b.login == CopilotAssigneeLogin { return fmt.Sprintf("%s (AI)", CopilotActorName) @@ -1151,14 +1188,17 @@ func (b AssignableBot) DisplayName() string { return b.Login() } +// ID returns the node ID of the bot. func (b AssignableBot) ID() string { return b.id } +// Login returns the login name of the bot. func (b AssignableBot) Login() string { return b.login } +// Name returns an empty string as bots do not have display names. func (b AssignableBot) Name() string { return "" } @@ -1281,6 +1321,7 @@ func RepoAssignableActors(client *Client, repo ghrepo.Interface) ([]AssignableAc return actors, nil } +// RepoLabel represents a label in a repository. type RepoLabel struct { ID string Name string @@ -1324,6 +1365,7 @@ func RepoLabels(client *Client, repo ghrepo.Interface) ([]RepoLabel, error) { return labels, nil } +// RepoMilestone represents a milestone in a repository. type RepoMilestone struct { ID string Title string @@ -1485,6 +1527,7 @@ func v2Projects(client *Client, repo ghrepo.Interface) ([]ProjectV2, error) { return projectsV2, nil } +// CreateRepoTransformToV4 creates a repository via the REST API and transforms the v3 response into a v4-style Repository. func CreateRepoTransformToV4(apiClient *Client, hostname string, method string, path string, body io.Reader) (*Repository, error) { var responsev3 repositoryV3 err := apiClient.REST(hostname, method, path, body, &responsev3) @@ -1542,6 +1585,7 @@ func GetRepoIDs(client *Client, host string, repositories []ghrepo.Interface) ([ return result, nil } +// RepoExists checks whether a repository exists by making a HEAD request to the REST API. func RepoExists(client *Client, repo ghrepo.Interface) (bool, error) { path := fmt.Sprintf("%srepos/%s/%s", ghinstance.RESTPrefix(repo.RepoHost()), repo.RepoOwner(), repo.RepoName()) diff --git a/api/queries_user.go b/api/queries_user.go index dd7be0105..9f1bf7a7c 100644 --- a/api/queries_user.go +++ b/api/queries_user.go @@ -1,9 +1,11 @@ package api +// Organization represents a GitHub organization with a login name. type Organization struct { Login string } +// CurrentLoginName returns the login name of the currently authenticated user. func CurrentLoginName(client *Client, hostname string) (string, error) { var query struct { Viewer struct { @@ -14,6 +16,7 @@ func CurrentLoginName(client *Client, hostname string) (string, error) { return query.Viewer.Login, err } +// CurrentLoginNameAndOrgs returns the login name and organization memberships of the currently authenticated user. func CurrentLoginNameAndOrgs(client *Client, hostname string) (string, []string, error) { var query struct { Viewer struct { @@ -34,6 +37,7 @@ func CurrentLoginNameAndOrgs(client *Client, hostname string) (string, []string, return query.Viewer.Login, orgNames, nil } +// CurrentUserID returns the node ID of the currently authenticated user. func CurrentUserID(client *Client, hostname string) (string, error) { var query struct { Viewer struct { diff --git a/api/query_builder.go b/api/query_builder.go index c3e1e9ba3..341967bee 100644 --- a/api/query_builder.go +++ b/api/query_builder.go @@ -205,6 +205,7 @@ var autoMergeRequest = shortenQuery(` } `) +// StatusCheckRollupGraphQLWithCountByState returns a GraphQL query fragment for status check rollup counts grouped by state. func StatusCheckRollupGraphQLWithCountByState() string { return shortenQuery(` statusCheckRollup: commits(last: 1) { @@ -229,6 +230,7 @@ func StatusCheckRollupGraphQLWithCountByState() string { }`) } +// StatusCheckRollupGraphQLWithoutCountByState returns a GraphQL query fragment for status check rollup with individual check nodes. func StatusCheckRollupGraphQLWithoutCountByState(after string) string { var afterClause string if after != "" { @@ -267,6 +269,7 @@ func StatusCheckRollupGraphQLWithoutCountByState(after string) string { }`), afterClause) } +// RequiredStatusCheckRollupGraphQL returns a GraphQL query fragment for required status checks filtered by pull request ID. func RequiredStatusCheckRollupGraphQL(prID, after string, includeEvent bool) string { var afterClause string if after != "" { @@ -342,8 +345,10 @@ var issueOnlyFields = []string{ "closedByPullRequestsReferences", } +// IssueFields is the list of all known issue field names for GraphQL queries. var IssueFields = append(sharedIssuePRFields, issueOnlyFields...) +// PullRequestFields is the list of all known pull request field names for GraphQL queries. var PullRequestFields = append(sharedIssuePRFields, "additions", "autoMergeRequest", @@ -452,6 +457,7 @@ func PullRequestGraphQL(fields []string) string { return IssueGraphQL(s.ToSlice()) } +// RepositoryFields is the list of all known repository field names for GraphQL queries. var RepositoryFields = []string{ "id", "name", @@ -531,6 +537,7 @@ var RepositoryFields = []string{ // "collaborators", // does it make sense to expose without affiliation filter? } +// RepositoryGraphQL constructs a GraphQL query fragment for a set of repository fields. func RepositoryGraphQL(fields []string) string { var q []string for _, field := range fields { diff --git a/api/reaction_groups.go b/api/reaction_groups.go index 08ae53040..a3769d24b 100644 --- a/api/reaction_groups.go +++ b/api/reaction_groups.go @@ -5,8 +5,10 @@ import ( "encoding/json" ) +// ReactionGroups is a slice of ReactionGroup entries for an issue or comment. type ReactionGroups []ReactionGroup +// MarshalJSON serializes ReactionGroups to JSON, omitting groups with zero reactions. func (rg ReactionGroups) MarshalJSON() ([]byte, error) { buf := bytes.Buffer{} buf.WriteRune('[') @@ -30,19 +32,23 @@ func (rg ReactionGroups) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } +// ReactionGroup represents a single emoji reaction type and its associated users. type ReactionGroup struct { Content string `json:"content"` Users ReactionGroupUsers `json:"users"` } +// ReactionGroupUsers holds the total count of users who reacted with a particular emoji. type ReactionGroupUsers struct { TotalCount int `json:"totalCount"` } +// Count returns the total number of users who reacted with this emoji. func (rg ReactionGroup) Count() int { return rg.Users.TotalCount } +// Emoji returns the Unicode emoji character for this reaction group's content type. func (rg ReactionGroup) Emoji() string { return reactionEmoji[rg.Content] }