Skip to content

Commit

Permalink
Merge branch 'trunk' into jungaretti/fix-jupyter-spinner
Browse files Browse the repository at this point in the history
  • Loading branch information
jungaretti committed Mar 7, 2023
2 parents 6a150d5 + 44b0218 commit 5a7f779
Show file tree
Hide file tree
Showing 119 changed files with 2,347 additions and 1,208 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ builds:
- -s -w -X github.com/cli/cli/v2/internal/build.Version={{.Version}} -X github.com/cli/cli/v2/internal/build.Date={{time "2006-01-02"}}
id: macos
goos: [darwin]
goarch: [amd64]
goarch: [amd64, arm64]

- <<: *build_defaults
id: linux
Expand Down
16 changes: 16 additions & 0 deletions api/export_pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ func (issue *Issue) ExportData(fields []string) map[string]interface{} {
data[f] = issue.Labels.Nodes
case "projectCards":
data[f] = issue.ProjectCards.Nodes
case "projectItems":
items := make([]map[string]interface{}, 0, len(issue.ProjectItems.Nodes))
for _, n := range issue.ProjectItems.Nodes {
items = append(items, map[string]interface{}{
"title": n.Project.Title,
})
}
data[f] = items
default:
sf := fieldByName(v, f)
data[f] = sf.Interface()
Expand Down Expand Up @@ -96,6 +104,14 @@ func (pr *PullRequest) ExportData(fields []string) map[string]interface{} {
data[f] = pr.Labels.Nodes
case "projectCards":
data[f] = pr.ProjectCards.Nodes
case "projectItems":
items := make([]map[string]interface{}, 0, len(pr.ProjectItems.Nodes))
for _, n := range pr.ProjectItems.Nodes {
items = append(items, map[string]interface{}{
"title": n.Project.Title,
})
}
data[f] = items
case "reviews":
data[f] = pr.Reviews.Nodes
case "latestReviews":
Expand Down
24 changes: 24 additions & 0 deletions api/export_pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,30 @@ func TestIssue_ExportData(t *testing.T) {
}
`),
},
{
name: "project items",
fields: []string{"projectItems"},
inputJSON: heredoc.Doc(`
{ "projectItems": { "nodes": [
{
"id": "PVTI_id",
"project": {
"id": "PVT_id",
"title": "Some Project"
}
}
] } }
`),
outputJSON: heredoc.Doc(`
{
"projectItems": [
{
"title": "Some Project"
}
]
}
`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions api/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

type tokenGetter interface {
AuthToken(string) (string, string)
Token(string) (string, string)
}

type HTTPClientOptions struct {
Expand Down Expand Up @@ -93,7 +93,7 @@ func AddAuthTokenHeader(rt http.RoundTripper, cfg tokenGetter) http.RoundTripper
// If the header is already set in the request, don't overwrite it.
if req.Header.Get(authorization) == "" {
hostname := ghinstance.NormalizeHostname(getHost(req))
if token, _ := cfg.AuthToken(hostname); token != "" {
if token, _ := cfg.Token(hostname); token != "" {
req.Header.Set(authorization, fmt.Sprintf("token %s", token))
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/http_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func TestNewHTTPClient(t *testing.T) {

type tinyConfig map[string]string

func (c tinyConfig) AuthToken(host string) (string, string) {
func (c tinyConfig) Token(host string) (string, string) {
return c[fmt.Sprintf("%s:%s", host, "oauth_token")], "oauth_token"
}

Expand Down
39 changes: 0 additions & 39 deletions api/queries_org.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,45 +42,6 @@ func OrganizationProjects(client *Client, repo ghrepo.Interface) ([]RepoProject,
return projects, nil
}

// OrganizationProjectsV2 fetches all open projectsV2 for an organization.
func OrganizationProjectsV2(client *Client, repo ghrepo.Interface) ([]RepoProjectV2, error) {
type responseData struct {
Organization struct {
ProjectsV2 struct {
Nodes []RepoProjectV2
PageInfo struct {
HasNextPage bool
EndCursor string
}
} `graphql:"projectsV2(first: 100, orderBy: {field: TITLE, direction: ASC}, after: $endCursor, query: $query)"`
} `graphql:"organization(login: $owner)"`
}

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

var projectsV2 []RepoProjectV2
for {
var query responseData
err := client.Query(repo.RepoHost(), "OrganizationProjectV2List", &query, variables)
if err != nil {
return nil, err
}

projectsV2 = append(projectsV2, query.Organization.ProjectsV2.Nodes...)

if !query.Organization.ProjectsV2.PageInfo.HasNextPage {
break
}
variables["endCursor"] = githubv4.String(query.Organization.ProjectsV2.PageInfo.EndCursor)
}

return projectsV2, nil
}

type OrgTeam struct {
ID string
Slug string
Expand Down
127 changes: 127 additions & 0 deletions api/queries_projects_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@ import (

const (
errorProjectsV2ReadScope = "field requires one of the following scopes: ['read:project']"
errorProjectsV2UserField = "Field 'projectsV2' doesn't exist on type 'User'"
errorProjectsV2RepositoryField = "Field 'projectsV2' doesn't exist on type 'Repository'"
errorProjectsV2OrganizationField = "Field 'projectsV2' doesn't exist on type 'Organization'"
errorProjectsV2IssueField = "Field 'projectItems' doesn't exist on type 'Issue'"
errorProjectsV2PullRequestField = "Field 'projectItems' doesn't exist on type 'PullRequest'"
)

type ProjectV2 struct {
ID string `json:"id"`
Title string `json:"title"`
Number int `json:"number"`
ResourcePath string `json:"resourcePath"`
Closed bool `json:"closed"`
}

// UpdateProjectV2Items uses the addProjectV2ItemById and the deleteProjectV2Item mutations
// to add and delete items from projects. The addProjectItems and deleteProjectItems arguments are
// mappings between a project and an item. This function can be used across multiple projects
Expand Down Expand Up @@ -126,6 +135,123 @@ func ProjectsV2ItemsForPullRequest(client *Client, repo ghrepo.Interface, pr *Pu
return nil
}

// OrganizationProjectsV2 fetches all open projectsV2 for an organization.
func OrganizationProjectsV2(client *Client, repo ghrepo.Interface) ([]ProjectV2, error) {
type responseData struct {
Organization struct {
ProjectsV2 struct {
Nodes []ProjectV2
PageInfo struct {
HasNextPage bool
EndCursor string
}
} `graphql:"projectsV2(first: 100, orderBy: {field: TITLE, direction: ASC}, after: $endCursor, query: $query)"`
} `graphql:"organization(login: $owner)"`
}

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

var projectsV2 []ProjectV2
for {
var query responseData
err := client.Query(repo.RepoHost(), "OrganizationProjectV2List", &query, variables)
if err != nil {
return nil, err
}

projectsV2 = append(projectsV2, query.Organization.ProjectsV2.Nodes...)

if !query.Organization.ProjectsV2.PageInfo.HasNextPage {
break
}
variables["endCursor"] = githubv4.String(query.Organization.ProjectsV2.PageInfo.EndCursor)
}

return projectsV2, nil
}

// RepoProjectsV2 fetches all open projectsV2 for a repository.
func RepoProjectsV2(client *Client, repo ghrepo.Interface) ([]ProjectV2, error) {
type responseData struct {
Repository struct {
ProjectsV2 struct {
Nodes []ProjectV2
PageInfo struct {
HasNextPage bool
EndCursor string
}
} `graphql:"projectsV2(first: 100, orderBy: {field: TITLE, direction: ASC}, after: $endCursor, query: $query)"`
} `graphql:"repository(owner: $owner, name: $name)"`
}

variables := map[string]interface{}{
"owner": githubv4.String(repo.RepoOwner()),
"name": githubv4.String(repo.RepoName()),
"endCursor": (*githubv4.String)(nil),
"query": githubv4.String("is:open"),
}

var projectsV2 []ProjectV2
for {
var query responseData
err := client.Query(repo.RepoHost(), "RepositoryProjectV2List", &query, variables)
if err != nil {
return nil, err
}

projectsV2 = append(projectsV2, query.Repository.ProjectsV2.Nodes...)

if !query.Repository.ProjectsV2.PageInfo.HasNextPage {
break
}
variables["endCursor"] = githubv4.String(query.Repository.ProjectsV2.PageInfo.EndCursor)
}

return projectsV2, nil
}

// CurrentUserProjectsV2 fetches all open projectsV2 for current user.
func CurrentUserProjectsV2(client *Client, hostname string) ([]ProjectV2, error) {
type responseData struct {
Viewer struct {
ProjectsV2 struct {
Nodes []ProjectV2
PageInfo struct {
HasNextPage bool
EndCursor string
}
} `graphql:"projectsV2(first: 100, orderBy: {field: TITLE, direction: ASC}, after: $endCursor, query: $query)"`
} `graphql:"viewer"`
}

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

var projectsV2 []ProjectV2
for {
var query responseData
err := client.Query(hostname, "UserProjectV2List", &query, variables)
if err != nil {
return nil, err
}

projectsV2 = append(projectsV2, query.Viewer.ProjectsV2.Nodes...)

if !query.Viewer.ProjectsV2.PageInfo.HasNextPage {
break
}
variables["endCursor"] = githubv4.String(query.Viewer.ProjectsV2.PageInfo.EndCursor)
}

return projectsV2, nil
}

// When querying ProjectsV2 fields we generally dont want to show the user
// scope errors and field does not exist errors. ProjectsV2IgnorableError
// checks against known error strings to see if an error can be safely ignored.
Expand All @@ -134,6 +260,7 @@ func ProjectsV2ItemsForPullRequest(client *Client, repo ghrepo.Interface, pr *Pu
func ProjectsV2IgnorableError(err error) bool {
msg := err.Error()
if strings.Contains(msg, errorProjectsV2ReadScope) ||
strings.Contains(msg, errorProjectsV2UserField) ||
strings.Contains(msg, errorProjectsV2RepositoryField) ||
strings.Contains(msg, errorProjectsV2OrganizationField) ||
strings.Contains(msg, errorProjectsV2IssueField) ||
Expand Down

0 comments on commit 5a7f779

Please sign in to comment.