Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
de59f6a
Add flags to add additional metadata to `issue create`
mislav Apr 15, 2020
d3a89b8
Expand `issue create` metadata flags to `pr create`
mislav Apr 17, 2020
39c4a5b
Remove unnecessary nil check
mislav Apr 17, 2020
a7d0617
Add ability to prefetch granulated repository metadata
mislav Apr 21, 2020
6ed50c6
Prefetch metadata in parallel
mislav Apr 22, 2020
42baf4c
Support org projects and team reviewers
mislav Apr 27, 2020
90c8e0e
Merge remote-tracking branch 'origin/master' into issue-pr-create-met…
mislav Apr 27, 2020
c6d8a4c
Fix mutations
mislav Apr 27, 2020
aeb0852
Add wizard that prompts for issue/pr metadata on create
mislav Apr 27, 2020
2089b15
Fix pagination when fetching metadata
mislav May 4, 2020
b59407d
Merge remote-tracking branch 'origin/master' into issue-pr-create-met…
mislav May 4, 2020
0bf4f16
Merge branch 'issue-pr-create-metadata' into issue-pr-create-metadata…
mislav May 4, 2020
d0f168f
Merge remote-tracking branch 'origin/master' into issue-pr-create-met…
mislav May 8, 2020
72e99e9
Merge branch 'issue-pr-create-metadata' into issue-pr-create-metadata…
mislav May 8, 2020
7160361
Rename `titleBody` (now a misnomer) to something more descriptive
mislav May 8, 2020
df14492
Rename `data` variable to something more descriptive
mislav May 8, 2020
cedf94f
Name some values for readability
mislav May 8, 2020
34fc345
Skip interactive mode in `pr create` if title & body were passed
mislav May 8, 2020
1f774b4
Add spinner while loading metadata
mislav May 8, 2020
d7e6d21
Order projects, teams, and labels by name
mislav May 8, 2020
1128439
`issue/pr create`: hide "Add metadata" if viewer does not have triage…
mislav May 8, 2020
8c84d68
Avoid aborting survey if reviewers/assignees/labels/projects/mileston…
mislav May 8, 2020
4a3588d
Merge pull request #839 from cli/issue-pr-create-metadata-wizard
mislav May 8, 2020
c682d90
Add tests for `issue/pr create` with metadata
mislav May 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 87 additions & 1 deletion api/queries_org.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package api

import "fmt"
import (
"context"
"fmt"

"github.com/shurcooL/githubv4"
)

// using API v3 here because the equivalent in GraphQL needs `read:org` scope
func resolveOrganization(client *Client, orgName string) (string, error) {
Expand All @@ -22,3 +27,84 @@ func resolveOrganizationTeam(client *Client, orgName, teamSlug string) (string,
err := client.REST("GET", fmt.Sprintf("orgs/%s/teams/%s", orgName, teamSlug), nil, &response)
return response.Organization.NodeID, response.NodeID, err
}

// OrganizationProjects fetches all open projects for an organization
func OrganizationProjects(client *Client, owner string) ([]RepoProject, error) {
var query struct {
Organization struct {
Projects struct {
Nodes []RepoProject
PageInfo struct {
HasNextPage bool
EndCursor string
}
} `graphql:"projects(states: [OPEN], first: 100, orderBy: {field: NAME, direction: ASC}, after: $endCursor)"`
} `graphql:"organization(login: $owner)"`
}

variables := map[string]interface{}{
"owner": githubv4.String(owner),
"endCursor": (*githubv4.String)(nil),
}

v4 := githubv4.NewClient(client.http)

var projects []RepoProject
for {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not used to golang's "while" loops

err := v4.Query(context.Background(), &query, variables)
if err != nil {
return nil, err
}

projects = append(projects, query.Organization.Projects.Nodes...)
if !query.Organization.Projects.PageInfo.HasNextPage {
break
}
variables["endCursor"] = githubv4.String(query.Organization.Projects.PageInfo.EndCursor)
}

return projects, nil
}

type OrgTeam struct {
ID string
Slug string
}

// OrganizationTeams fetches all the teams in an organization
func OrganizationTeams(client *Client, owner string) ([]OrgTeam, error) {
var query struct {
Organization struct {
Teams struct {
Nodes []OrgTeam
PageInfo struct {
HasNextPage bool
EndCursor string
}
} `graphql:"teams(first: 100, orderBy: {field: NAME, direction: ASC}, after: $endCursor)"`
} `graphql:"organization(login: $owner)"`
}

variables := map[string]interface{}{
"owner": githubv4.String(owner),
"endCursor": (*githubv4.String)(nil),
}

v4 := githubv4.NewClient(client.http)

var teams []OrgTeam
for {
err := v4.Query(context.Background(), &query, variables)
if err != nil {
return nil, err
}

teams = append(teams, query.Organization.Teams.Nodes...)
if !query.Organization.Teams.PageInfo.HasNextPage {
break
}
variables["endCursor"] = githubv4.String(query.Organization.Teams.PageInfo.EndCursor)
}

return teams, nil
}
70 changes: 68 additions & 2 deletions api/queries_pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter
mutation CreatePullRequest($input: CreatePullRequestInput!) {
createPullRequest(input: $input) {
pullRequest {
id
url
}
}
Expand All @@ -588,7 +589,10 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter
"repositoryId": repo.ID,
}
for key, val := range params {
inputParams[key] = val
switch key {
case "title", "body", "draft", "baseRefName", "headRefName":
inputParams[key] = val
}
}
variables := map[string]interface{}{
"input": inputParams,
Expand All @@ -604,8 +608,70 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter
if err != nil {
return nil, err
}
pr := &result.CreatePullRequest.PullRequest

// metadata parameters aren't currently available in `createPullRequest`,
// but they are in `updatePullRequest`
updateParams := make(map[string]interface{})
for key, val := range params {
switch key {
case "assigneeIds", "labelIds", "projectIds", "milestoneId":
if !isBlank(val) {
updateParams[key] = val
}
}
}
if len(updateParams) > 0 {
updateQuery := `
mutation UpdatePullRequest($input: UpdatePullRequestInput!) {
updatePullRequest(input: $input) { clientMutationId }
}`
updateParams["pullRequestId"] = pr.ID
variables := map[string]interface{}{
"input": updateParams,
}
err := client.GraphQL(updateQuery, variables, &result)
if err != nil {
return nil, err
}
}

return &result.CreatePullRequest.PullRequest, nil
// reviewers are requested in yet another additional mutation
reviewParams := make(map[string]interface{})
if ids, ok := params["userReviewerIds"]; ok && !isBlank(ids) {
reviewParams["userIds"] = ids
}
if ids, ok := params["teamReviewerIds"]; ok && !isBlank(ids) {
reviewParams["teamIds"] = ids
}

if len(reviewParams) > 0 {
reviewQuery := `
mutation RequestReviews($input: RequestReviewsInput!) {
requestReviews(input: $input) { clientMutationId }
}`
reviewParams["pullRequestId"] = pr.ID
variables := map[string]interface{}{
"input": reviewParams,
}
err := client.GraphQL(reviewQuery, variables, &result)
if err != nil {
return nil, err
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it looks like the reviewQuery and the updateQuery are not dependent on each other, I was wondering if we could combine the queries and variables and just make one call to the server?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting suggestion! That should definitely be possible, even though we don't have a clean mechanism of merging GraphQL queries just yet. I will look into whether this is feasible


return pr, nil
}

func isBlank(v interface{}) bool {
switch vv := v.(type) {
case string:
return vv == ""
case []string:
return len(vv) == 0
default:
return true
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very handy!

}

func AddReview(client *Client, pr *PullRequest, input *PullRequestReviewInput) error {
Expand Down
Loading